* Changed README.md

* Changed docs notebooks

---------

Co-authored-by: Inga Ulusoy <inga.ulusoy@uni-heidelberg.de>
Этот коммит содержится в:
Petr Andriushchenko 2023-10-30 16:18:07 +01:00 коммит произвёл GitHub
родитель 8287f35696
Коммит fe1e937f18
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
20 изменённых файлов: 692 добавлений и 1146 удалений

Просмотреть файл

@ -38,9 +38,11 @@ The `AMMICO` package can be installed using pip:
```
pip install ammico
```
This will install the package and its dependencies locally.
This will install the package and its dependencies locally. If after installation you get some errors when running some modules, please follow the instructions below.
Some ammico components require tensorflow (e.g. Emotion detector), some pytorch (e.g. Summary detector). Sometimes there are compatibility problems between these two frameworks. To avoid compatibility problems on your machines, we suggest you to follow these steps before installing the package (you need conda on your machine):
## Compatibility problems solving
Some ammico components require `tensorflow` (e.g. Emotion detector), some `pytorch` (e.g. Summary detector). Sometimes there are compatibility problems between these two frameworks. To avoid these problems on your machines, you can prepare proper environment before installing the package (you need conda on your machine):
### 1. First, install tensorflow (https://www.tensorflow.org/install/pip)
- create a new environment with python and activate it
@ -68,7 +70,7 @@ Some ammico components require tensorflow (e.g. Emotion detector), some pytorch
```conda activate ammico_env ```
- and now we can install tensorflow
- install tensorflow
```python -m pip install tensorflow==2.12.1```
@ -85,7 +87,7 @@ Some ammico components require tensorflow (e.g. Emotion detector), some pytorch
It is done.
### Micromamba
If you have micromamba on your machine you can prepare environment with just one command:
If you are using micromamba you can prepare environment with just one command:
```micromamba create --no-channel-priority -c nvidia -c pytorch -c conda-forge -n ammico_env "python=3.10" pytorch torchvision torchaudio pytorch-cuda "tensorflow-gpu<=2.12.3" "numpy<=1.23.4"```

Просмотреть файл

@ -4,9 +4,12 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# AMMICO: AI Media and Misinformation Content Analysis Tool\n",
"# AMMICO Demonstration Notebook\n",
"With ammico, you can analyze text on images and image content at the same time. This is a demonstration notebook to showcase the capabilities of ammico.\n",
"You can run this notebook on google colab or locally / on your own HPC resource. The first cell only runs on google colab; on all other machines, you need to create a conda environment first and install ammico from the Python Package Index using `pip install ammico`."
"You can run this notebook on google colab or locally / on your own HPC resource. The first cell only runs on google colab; on all other machines, you need to create a conda environment first and install ammico from the Python Package Index using \n",
"```pip install ammico``` \n",
"Alternatively you can install the development version from the GitHub repository \n",
"```pip install git+https://github.com/ssciwr/AMMICO.git```"
]
},
{
@ -53,11 +56,15 @@
"source": [
"# Step 1: Read your data into AMMICO\n",
"The ammico package reads in one or several input files given in a folder for processing. The user can select to read in all image files in a folder, to include subfolders via the `recursive` option, and can select the file extension that should be considered (for example, only \"jpg\" files, or both \"jpg\" and \"png\" files). For reading in the files, the ammico function `find_files` is used, with optional keywords:\n",
"- `path` - the directory containing the image files (defaults to the location set by environment variable `AMMICO_DATA_HOME`); \n",
"- `pattern` - the file extensions that should be considered when reading in the data (defaults to all allowed file extensions, that is \"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"avif\", \"tiff\")\n",
"- `recursive` - include subdirectories recursively (defaults to `True`)\n",
"- `limit` - the maximum number of files that should be read. This is useful for testing, if you want to run the analysis on only a few input files (defaults to 20, to return all images that are found set to `None` or `-1`)\n",
"- `random_seed` - the random seed used for shuffling the images. This is useful if you select only a few images to be read and want to preserve the order and selection (defaults to `None`)\n",
"\n",
"| input key | input type | possible input values |\n",
"| --------- | ---------- | --------------------- |\n",
"`path` | `str` | the directory containing the image files (defaults to the location set by environment variable `AMMICO_DATA_HOME`) |\n",
"| `pattern` | `str\\|list` | the file extensions to consider (defaults to \"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"avif\", \"tiff\") |\n",
"| `recursive` | `bool` | include subdirectories recursively (defaults to `True`) |\n",
"| `limit` | `int` | maximum number of files to read (defaults to `20`, for all images set to `None` or `-1`) |\n",
"| `random_seed` | `str` | the random seed for shuffling the images; applies when only a few images are read and the selection should be preserved (defaults to `None`) |\n",
"\n",
"The `find_files` function returns a nested dict that contains the file ids and the paths to the files and is empty otherwise. This dict is filled step by step with more data as each detector class is run on the data (see below)."
]
},
@ -69,7 +76,7 @@
"source": [
"image_dict = ammico.find_files(\n",
" path=\"/content/drive/MyDrive/misinformation-data/\",\n",
" limit=10,\n",
" limit=2,\n",
")"
]
},
@ -136,8 +143,19 @@
"# initialize the models\n",
"summary_model, summary_vis_processors = ammico.SummaryDetector(image_dict).load_model(model_type=\"base\")\n",
"# run the analysis without having to re-iniatialize the model\n",
"for key in image_dict:\n",
" image_dict[key] = ammico.SummaryDetector(image_dict[key], analysis_type=\"summary\", summary_model=summary_model, summary_vis_processors=summary_vis_processors).analyse_image()"
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.SummaryDetector(image_dict[key], analysis_type=\"summary\", \n",
" summary_model=summary_model, \n",
" summary_vis_processors=summary_vis_processors).analyse_image()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This can be done in a separate loop or in the same loop as for text and emotion detection.\n",
"\n",
"The nested dictionary will be updated from containing only the file id's and paths to the image files, to containing also all the image data."
]
},
{
@ -196,23 +214,159 @@
"# The detector modules\n",
"The different detector modules with their options are explained in more detail in this section.\n",
"## Text detector\n",
"Text on the images can be extracted using the `TextDetector` class (`text` module). The text is initally extracted using the Google Cloud Vision API and then translated into English with googletrans. The translated text is cleaned of whitespace, linebreaks, and numbers using Python syntax and spaCy. The user can set if the text should be further summarized, and analyzed for sentiment and named entity recognition, by setting the keyword `analyse_text` to `True` (the default is `False`). If set, the transformers pipeline is used for each of these tasks, with the default models as of 03/2023. Other models can be selected by setting the optional keyword `model_names` to a list of selected models, on for each task: `model_names=[\"sshleifer/distilbart-cnn-12-6\", \"distilbert-base-uncased-finetuned-sst-2-english\", \"dbmdz/bert-large-cased-finetuned-conll03-english\"]` for summary, sentiment, and ner. To be even more specific, revision numbers can also be selected by specifying the optional keyword `revision_numbers` to a list of revision numbers for each model, for example `revision_numbers=[\"a4f8f3e\", \"af0f99b\", \"f2482bf\"]`.\n",
"Text on the images can be extracted using the `TextDetector` class (`text` module). The text is initally extracted using the Google Cloud Vision API and then translated into English with googletrans. The translated text is cleaned of whitespace, linebreaks, and numbers using Python syntax and spaCy. \n",
"\n",
"Summarizing, the text detection is carried out using the following method call and keywords, where `analyse_text`, `model_names`, and `revision_numbers` are optional:\n",
"```\n",
"image_dict[\"image_id\"] = ammico.TextDetector(image_dict[\"image_id\"], \n",
"<img src=\"../../docs/source/_static/text_detector.png\" width=\"800\" />\n",
"\n",
"The user can set if the text should be further summarized, and analyzed for sentiment and named entity recognition, by setting the keyword `analyse_text` to `True` (the default is `False`). If set, the transformers pipeline is used for each of these tasks, with the default models as of 03/2023. Other models can be selected by setting the optional keyword `model_names` to a list of selected models, on for each task: `model_names=[\"sshleifer/distilbart-cnn-12-6\", \"distilbert-base-uncased-finetuned-sst-2-english\", \"dbmdz/bert-large-cased-finetuned-conll03-english\"]` for summary, sentiment, and ner. To be even more specific, revision numbers can also be selected by specifying the optional keyword `revision_numbers` to a list of revision numbers for each model, for example `revision_numbers=[\"a4f8f3e\", \"af0f99b\", \"f2482bf\"]`. \n",
"\n",
"Please note that for the Google Cloud Vision API (the TextDetector class) you need to set a key in order to process the images. This key is ideally set as an environment variable using for example"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"] = \"/content/drive/MyDrive/misinformation-data/misinformation-campaign-981aa55a3b13.json\"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"where you place the key on your Google Drive if running on colab, or place it in a local folder on your machine.\n",
"\n",
"Summarizing, the text detection is carried out using the following method call and keywords, where `analyse_text`, `model_names`, and `revision_numbers` are optional:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.TextDetector(image_dict[key], \n",
" analyse_text=True, model_names=[\"sshleifer/distilbart-cnn-12-6\", \n",
" \"distilbert-base-uncased-finetuned-sst-2-english\", \n",
" \"dbmdz/bert-large-cased-finetuned-conll03-english\"], \n",
" revision_numbers=[\"a4f8f3e\", \"af0f99b\", \"f2482bf\"]).analyse_image()\n",
"```\n",
" revision_numbers=[\"a4f8f3e\", \"af0f99b\", \"f2482bf\"]).analyse_image()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The models can be adapted interactively in the notebook interface and the best models can then be used in a subsequent analysis of the whole data set.\n",
"\n",
"A detailed description of the output keys and data types is given in the following table.\n",
"\n",
"| output key | output type | output value |\n",
"| ---------- | ----------- | ------------ |\n",
"| `text` | `str` | the extracted text in the original language |\n",
"| `text_language` | `str` | the detected dominant language of the extracted text |\n",
"| `text_english` | `str` | the text translated into English |\n",
"| `text_clean` | `str` | the text after cleaning from numbers and unrecognizable words |\n",
"| `text_summary` | `str` | the summary of the text, generated with a transformers model |\n",
"| `sentiment` | `str` | the detected sentiment, generated with a transformers model |\n",
"| `sentiment_score` | `float` | the confidence associated with the predicted sentiment |\n",
"| `entity` | `list[str]` | the detected named entities, generated with a transformers model |\n",
"| `entity_type` | `list[str]` | the detected entity type |\n",
"\n",
"## Image summary and query\n",
"\n",
"The `SummaryDetector` can be used to generate image captions (`summary`) as well as visual question answering (`VQA`). \n",
"\n",
"<img src=\"../../docs/source/_static/summary_detector.png\" width=\"800\" />\n",
"\n",
"This module is based on the [LAVIS](https://github.com/salesforce/LAVIS) library. Since the models can be quite large, an initial object is created which will load the necessary models into RAM/VRAM and then use them in the analysis. The user can specify the type of analysis to be performed using the `analysis_type` keyword. Setting it to `summary` will generate a caption (summary), `questions` will prepare answers (VQA) to a list of questions as set by the user, `summary_and_questions` will do both. Note that the desired analysis type needs to be set here in the initialization of the \n",
"detector object, and not when running the analysis for each image; the same holds true for the selected model."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_summary_detector = ammico.SummaryDetector(image_dict, analysis_type=\"summary\", model_type=\"base\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The implemented models are listed below.\n",
"\n",
"| input model name | model |\n",
"| ---------------- | ----- |\n",
"| base | BLIP image captioning base, ViT-B/16, pretrained on COCO dataset |\n",
"| large | BLIP image captioning large, ViT-L/16, pretrained on COCO dataset |\n",
"| vqa | BLIP base model fine-tuned on VQA v2.0 dataset |\n",
"| blip2_t5_pretrain_flant5xxl | BLIP2 pretrained on FlanT5<sub>XXL</sub> | \n",
"| blip2_t5_pretrain_flant5xl | BLIP2 pretrained on FlanT5<sub>XL</sub> | \n",
"| blip2_t5_caption_coco_flant5xl | BLIP2 pretrained on FlanT5<sub>XL</sub>, fine-tuned on COCO | \n",
"| blip2_opt_pretrain_opt2.7b | BLIP2 pretrained on OPT-2.7b |\n",
"| blip2_opt_pretrain_opt6.7b | BLIP2 pretrained on OPT-6.7b | \n",
"| blip2_opt_caption_coco_opt2.7b | BLIP2 pretrained on OPT-2.7b, fine-tuned on COCO | \n",
"| blip2_opt_caption_coco_opt6.7b | BLIP2 pretrained on OPT-6.7b, fine-tuned on COCO |\n",
"\n",
"For VQA, a list of questions needs to be passed when carrying out the analysis; these should be given as a list of strings."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"list_of_questions = [\n",
" \"How many persons on the picture?\",\n",
" \"Are there any politicians in the picture?\",\n",
" \"Does the picture show something from medicine?\",\n",
"]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Summarizing, the detector is run as"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_summary_vqa_detector = ammico.SummaryDetector(image_dict, analysis_type=\"summary_and_questions\", \n",
" model_type=\"base\")\n",
"for key in image_dict.keys():\n",
" image_dict[key] = image_summary_vqa_detector.analyse_image(image_dict[key], \n",
" analysis_type=\"summary_and_questions\", \n",
" list_of_questions = list_of_questions)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The output is given as a dictionary with the following keys and data types:\n",
"\n",
"| output key | output type | output value |\n",
"| ---------- | ----------- | ------------ |\n",
"| `const_image_summary` | `str` | when `analysis_type=\"summary\"` or `\"summary_and_questions\"`, constant image caption (does not change upon re-running the analysis for the same model) |\n",
"| `3_non-deterministic_summary` | `list[str]` | when `analysis_type=\"summary\"` or s`ummary_and_questions`, three different captions generated with different random seeds |\n",
"| *a user-defined input question* | `str` | when `analysis_type=\"questions\"` or `summary_and_questions`, the answer to the user-defined input question | \n",
"\n",
"## Detection of faces and facial expression analysis\n",
"Faces and facial expressions are detected and analyzed using the `EmotionDetector` class from the `faces` module. Initially, it is detected if faces are present on the image using RetinaFace, followed by analysis if face masks are worn (Face-Mask-Detection). The detection of age, gender, race, and emotions is carried out with deepface.\n",
"\n",
"<img src=\"../../docs/source/_static/emotion_detector.png\" width=\"800\" />\n",
"\n",
"Depending on the features found on the image, the face detection module returns a different analysis content: If no faces are found on the image, all further steps are skipped and the result `\"face\": \"No\", \"multiple_faces\": \"No\", \"no_faces\": 0, \"wears_mask\": [\"No\"], \"age\": [None], \"gender\": [None], \"race\": [None], \"emotion\": [None], \"emotion (category)\": [None]` is returned. If one or several faces are found, up to three faces are analyzed if they are partially concealed by a face mask. If yes, only age and gender are detected; if no, also race, emotion, and dominant emotion are detected. In case of the latter, the output could look like this: `\"face\": \"Yes\", \"multiple_faces\": \"Yes\", \"no_faces\": 2, \"wears_mask\": [\"No\", \"No\"], \"age\": [27, 28], \"gender\": [\"Man\", \"Man\"], \"race\": [\"asian\", None], \"emotion\": [\"angry\", \"neutral\"], \"emotion (category)\": [\"Negative\", \"Neutral\"]`, where for the two faces that are detected (given by `no_faces`), some of the values are returned as a list with the first item for the first (largest) face and the second item for the second (smaller) face (for example, `\"emotion\"` returns a list `[\"angry\", \"neutral\"]` signifying the first face expressing anger, and the second face having a neutral expression).\n",
"\n",
"The emotion detection reports the seven facial expressions angry, fear, neutral, sad, disgust, happy and surprise. These emotions are assigned based on the returned confidence of the model (between 0 and 1), with a high confidence signifying a high likelihood of the detected emotion being correct. Emotion recognition is not an easy task, even for a human; therefore, we have added a keyword `emotion_threshold` signifying the % value above which an emotion is counted as being detected. The default is set to 50%, so that a confidence above 0.5 results in an emotion being assigned. If the confidence is lower, no emotion is assigned. \n",
@ -222,11 +376,38 @@
"A similar threshold as for the emotion recognition is set for the race detection, `race_threshold`, with the default set to 50% so that a confidence for the race above 0.5 only will return a value in the analysis. \n",
"\n",
"Summarizing, the face detection is carried out using the following method call and keywords, where `emotion_threshold` and \n",
"`race_threshold` are optional:\n",
"```\n",
"image_dict[\"image_id\"] = ammico.EmotionDetector(image_dict[\"image_id\"], emotion_threshold=50, race_threshold=50).analyse_image()\n",
"```\n",
"The thresholds can be adapted interactively in the notebook interface and the optimal value can then be used in a subsequent analysis of the whole data set."
"`race_threshold` are optional:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.EmotionDetector(image_dict[key], emotion_threshold=50, race_threshold=50).analyse_image()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The thresholds can be adapted interactively in the notebook interface and the optimal value can then be used in a subsequent analysis of the whole data set.\n",
"\n",
"The output keys that are generated are\n",
"\n",
"| output key | output type | output value |\n",
"| ---------- | ----------- | ------------ |\n",
"| `face` | `str` | if a face is detected |\n",
"| `multiple_faces` | `str` | if multiple faces are detected |\n",
"| `no_faces` | `int` | the number of detected faces |\n",
"| `wears_mask` | `list[str]` | if each of the detected faces wears a face covering, up to three faces |\n",
"| `age` | `list[int]` | the detected age, up to three faces |\n",
"| `gender` | `list[str]` | the detected gender, up to three faces |\n",
"| `race` | `list[str]` | the detected race, up to three faces, if above the confidence threshold |\n",
"| `emotion` | `list[str]` | the detected emotion, up to three faces, if above the confidence threshold |\n",
"| `emotion (category)` | `list[str]` | the detected emotion category (positive, negative, or neutral), up to three faces, if above the confidence threshold |"
]
},
{
@ -259,7 +440,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.12"
"version": "3.9.18"
}
},
"nbformat": 4,

Просмотреть файл

@ -138,8 +138,7 @@
"metadata": {},
"outputs": [],
"source": [
"outdict = ammico.append_data_to_dict(mydict)\n",
"df = ammico.dump_df(outdict)"
"df = ammico.get_dataframe(mydict)"
]
},
{

Просмотреть файл

@ -136,8 +136,7 @@
"metadata": {},
"outputs": [],
"source": [
"outdict = ammico.append_data_to_dict(mydict)\n",
"df = ammico.dump_df(outdict)"
"df = ammico.get_dataframe(mydict)"
]
},
{
@ -177,14 +176,6 @@
"source": [
"df.to_csv(\"/content/drive/MyDrive/misinformation-data/data_out.csv\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b1a80023",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {

Просмотреть файл

@ -164,8 +164,7 @@
"metadata": {},
"outputs": [],
"source": [
"outdict = ammico.append_data_to_dict(mydict)\n",
"df = ammico.dump_df(outdict)"
"df = ammico.get_dataframe(mydict)"
]
},
{
@ -339,14 +338,6 @@
"source": [
"topic_model.save(\"misinfo_posts\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7c94edb9",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {

Просмотреть файл

@ -116,7 +116,7 @@
"outputs": [],
"source": [
"for key in mydict:\n",
" mydict[key] = obj.analyse_image(analysis_type=\"summary\", subdict = mydict[key])"
" mydict[key] = obj.analyse_image(subdict = mydict[key], analysis_type=\"summary\")"
]
},
{
@ -148,8 +148,7 @@
},
"outputs": [],
"source": [
"outdict = ammico.append_data_to_dict(mydict)\n",
"df = ammico.dump_df(outdict)"
"df = ammico.get_dataframe(mydict)"
]
},
{
@ -287,8 +286,7 @@
"metadata": {},
"outputs": [],
"source": [
"outdict2 = ammico.append_data_to_dict(mydict)\n",
"df2 = ammico.dump_df(outdict2)"
"df2 = ammico.get_dataframe(mydict)"
]
},
{
@ -510,17 +508,7 @@
"metadata": {},
"outputs": [],
"source": [
"outdict = ammico.append_data_to_dict(mydict)\n",
"df = ammico.dump_df(outdict)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"mydict"
"df = ammico.get_dataframe(mydict)"
]
},
{

Просмотреть файл

@ -239,8 +239,8 @@ class SummaryDetector(AnalysisMethod):
def analyse_image(
self,
analysis_type: Optional[str] = None,
subdict: dict = None,
analysis_type: Optional[str] = None,
list_of_questions: Optional[list[str]] = None,
consequential_questions: bool = False,
):

Двоичные данные
docs/source/_static/emotion_detector.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 83 KiB

Двоичные данные
docs/source/_static/summary_detector.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 84 KiB

Двоичные данные
docs/source/_static/text_detector.png Обычный файл

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 70 KiB

Просмотреть файл

@ -33,23 +33,7 @@ faces module
color_analysis module
---------------------
.. automodule:: color_analysis
:members:
:undoc-members:
:show-inheritance:
objects module
--------------
.. automodule:: objects
:members:
:undoc-members:
:show-inheritance:
objects_cvlib module
--------------------
.. automodule:: objects_cvlib
.. automodule:: colors
:members:
:undoc-members:
:show-inheritance:

Просмотреть файл

@ -24,6 +24,14 @@ extensions = ["sphinx.ext.autodoc", "sphinx.ext.napoleon", "myst_parser", "nbsph
nbsphinx_allow_errors = True
napoleon_custom_sections = [("Returns", "params_style")]
html_context = {
"display_github": True, # Integrate GitHub
"github_user": "ssciwr", # Username
"github_repo": "AMMICO", # Repo name
"github_version": "main", # Version
"conf_py_path": "/source/", # Path in the checkout to the docs root
}
templates_path = ["_templates"]
exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]

Просмотреть файл

@ -11,12 +11,9 @@ Welcome to AMMICO's documentation!
:caption: Contents:
readme_link
notebooks/Example faces
notebooks/Example text
notebooks/Example summary
notebooks/DemoNotebook_ammico
notebooks/Example multimodal
notebooks/Example colors
notebooks/Example objects
notebooks/Example cropposts
modules
license_link

Просмотреть файл

@ -0,0 +1,447 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# AMMICO Demonstration Notebook\n",
"With ammico, you can analyze text on images and image content at the same time. This is a demonstration notebook to showcase the capabilities of ammico.\n",
"You can run this notebook on google colab or locally / on your own HPC resource. The first cell only runs on google colab; on all other machines, you need to create a conda environment first and install ammico from the Python Package Index using \n",
"```pip install ammico``` \n",
"Alternatively you can install the development version from the GitHub repository \n",
"```pip install git+https://github.com/ssciwr/AMMICO.git```"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# if running on google colab\n",
"# flake8-noqa-cell\n",
"import os\n",
"\n",
"if \"google.colab\" in str(get_ipython()):\n",
" # update python version\n",
" # install setuptools\n",
" # %pip install setuptools==61 -qqq\n",
" # install ammico\n",
" %pip install git+https://github.com/ssciwr/ammico.git -qqq\n",
" # mount google drive for data and API key\n",
" from google.colab import drive\n",
"\n",
" drive.mount(\"/content/drive\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Import the ammico package."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import ammico"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Step 1: Read your data into AMMICO\n",
"The ammico package reads in one or several input files given in a folder for processing. The user can select to read in all image files in a folder, to include subfolders via the `recursive` option, and can select the file extension that should be considered (for example, only \"jpg\" files, or both \"jpg\" and \"png\" files). For reading in the files, the ammico function `find_files` is used, with optional keywords:\n",
"\n",
"| input key | input type | possible input values |\n",
"| --------- | ---------- | --------------------- |\n",
"`path` | `str` | the directory containing the image files (defaults to the location set by environment variable `AMMICO_DATA_HOME`) |\n",
"| `pattern` | `str\\|list` | the file extensions to consider (defaults to \"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"avif\", \"tiff\") |\n",
"| `recursive` | `bool` | include subdirectories recursively (defaults to `True`) |\n",
"| `limit` | `int` | maximum number of files to read (defaults to `20`, for all images set to `None` or `-1`) |\n",
"| `random_seed` | `str` | the random seed for shuffling the images; applies when only a few images are read and the selection should be preserved (defaults to `None`) |\n",
"\n",
"The `find_files` function returns a nested dict that contains the file ids and the paths to the files and is empty otherwise. This dict is filled step by step with more data as each detector class is run on the data (see below)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_dict = ammico.find_files(\n",
" path=\"data/\",\n",
" limit=10,\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 2: Inspect the input files using the graphical user interface\n",
"A Dash user interface is to select the most suitable options for the analysis, before running a complete analysis on the whole data set. The options for each detector module are explained below in the corresponding sections; for example, different models can be selected that will provide slightly different results. This way, the user can interactively explore which settings provide the most accurate results. In the interface, the nested `image_dict` is passed through the `AnalysisExplorer` class. The interface is run on a specific port which is passed using the `port` keyword; if a port is already in use, it will return an error message, in which case the user should select a different port number. \n",
"The interface opens a dash app inside the Jupyter Notebook and allows selection of the input file in the top left dropdown menu, as well as selection of the detector type in the top right, with options for each detector type as explained below. The output of the detector is shown directly on the right next to the image. This way, the user can directly inspect how updating the options for each detector changes the computed results, and find the best settings for a production run.\n",
"\n",
"Please note that for the Google Cloud Vision API (the TextDetector class) you need to set a key in order to process the images. This key is ideally set as an environment variable using for example\n",
"```\n",
"os.environ[\n",
" \"GOOGLE_APPLICATION_CREDENTIALS\"\n",
"] = \"/content/drive/MyDrive/misinformation-data/misinformation-campaign-981aa55a3b13.json\"\n",
"```\n",
"where you place the key on your Google Drive if running on colab, or place it in a local folder on your machine."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"analysis_explorer = ammico.AnalysisExplorer(image_dict)\n",
"analysis_explorer.run_server(port=8055)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 3: Analyze all images\n",
"After having selected the best options for each detector module from the interactive GUI, the analysis can now be run in production on all images in the data set. Depending on the size of the data set and the computing resources available, this can take some time. Please note that you need to have set your Google Cloud Vision API key for the TextDetector to run.\n",
"The desired detector modules are called sequentially in any order, for example:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.TextDetector(image_dict[key], analyse_text=True).analyse_image()\n",
" image_dict[key] = ammico.EmotionDetector(image_dict[key]).analyse_image()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For the computationally demanding `SummaryDetector`, it is best to initialize the model first and then analyze each image while passing the model explicitly. This can be done in a separate loop or in the same loop as for text and emotion detection."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# initialize the models\n",
"summary_model, summary_vis_processors = ammico.SummaryDetector(image_dict).load_model(model_type=\"base\")\n",
"# run the analysis without having to re-iniatialize the model\n",
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.SummaryDetector(image_dict[key], analysis_type=\"summary\", \n",
" summary_model=summary_model, \n",
" summary_vis_processors=summary_vis_processors).analyse_image()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This can be done in a separate loop or in the same loop as for text and emotion detection.\n",
"\n",
"The nested dictionary will be updated from containing only the file id's and paths to the image files, to containing also all the image data."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 4: Convert analysis output to pandas dataframe and write csv\n",
"The content of the nested dictionary can then conveniently be converted into a pandas dataframe for further analysis in Python, or be written as a csv file:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_df = ammico.get_dataframe(image_dict)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Inspect the dataframe:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_df.head(3)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Or write to a csv file:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_df.to_csv(\"data_out.csv\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# The detector modules\n",
"The different detector modules with their options are explained in more detail in this section.\n",
"## Text detector\n",
"Text on the images can be extracted using the `TextDetector` class (`text` module). The text is initally extracted using the Google Cloud Vision API and then translated into English with googletrans. The translated text is cleaned of whitespace, linebreaks, and numbers using Python syntax and spaCy. \n",
"\n",
"<img src=\"../_static/text_detector.png\" width=\"800\" />\n",
"\n",
"The user can set if the text should be further summarized, and analyzed for sentiment and named entity recognition, by setting the keyword `analyse_text` to `True` (the default is `False`). If set, the transformers pipeline is used for each of these tasks, with the default models as of 03/2023. Other models can be selected by setting the optional keyword `model_names` to a list of selected models, on for each task: `model_names=[\"sshleifer/distilbart-cnn-12-6\", \"distilbert-base-uncased-finetuned-sst-2-english\", \"dbmdz/bert-large-cased-finetuned-conll03-english\"]` for summary, sentiment, and ner. To be even more specific, revision numbers can also be selected by specifying the optional keyword `revision_numbers` to a list of revision numbers for each model, for example `revision_numbers=[\"a4f8f3e\", \"af0f99b\", \"f2482bf\"]`. \n",
"\n",
"Please note that for the Google Cloud Vision API (the TextDetector class) you need to set a key in order to process the images. This key is ideally set as an environment variable using for example"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"os.environ[\"GOOGLE_APPLICATION_CREDENTIALS\"] = \"misinformation-campaign-981aa55a3b13.json\"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"where you place the key on your Google Drive if running on colab, or place it in a local folder on your machine.\n",
"\n",
"Summarizing, the text detection is carried out using the following method call and keywords, where `analyse_text`, `model_names`, and `revision_numbers` are optional:\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.TextDetector(image_dict[key], \n",
" analyse_text=True, model_names=[\"sshleifer/distilbart-cnn-12-6\", \n",
" \"distilbert-base-uncased-finetuned-sst-2-english\", \n",
" \"dbmdz/bert-large-cased-finetuned-conll03-english\"], \n",
" revision_numbers=[\"a4f8f3e\", \"af0f99b\", \"f2482bf\"]).analyse_image()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The models can be adapted interactively in the notebook interface and the best models can then be used in a subsequent analysis of the whole data set.\n",
"\n",
"A detailed description of the output keys and data types is given in the following table.\n",
"\n",
"| output key | output type | output value |\n",
"| ---------- | ----------- | ------------ |\n",
"| `text` | `str` | the extracted text in the original language |\n",
"| `text_language` | `str` | the detected dominant language of the extracted text |\n",
"| `text_english` | `str` | the text translated into English |\n",
"| `text_clean` | `str` | the text after cleaning from numbers and unrecognizable words |\n",
"| `text_summary` | `str` | the summary of the text, generated with a transformers model |\n",
"| `sentiment` | `str` | the detected sentiment, generated with a transformers model |\n",
"| `sentiment_score` | `float` | the confidence associated with the predicted sentiment |\n",
"| `entity` | `list[str]` | the detected named entities, generated with a transformers model |\n",
"| `entity_type` | `list[str]` | the detected entity type |\n",
"\n",
"## Image summary and query\n",
"\n",
"The `SummaryDetector` can be used to generate image captions (`summary`) as well as visual question answering (`VQA`). \n",
"\n",
"<img src=\"../_static/summary_detector.png\" width=\"800\" />\n",
"\n",
"This module is based on the [LAVIS](https://github.com/salesforce/LAVIS) library. Since the models can be quite large, an initial object is created which will load the necessary models into RAM/VRAM and then use them in the analysis. The user can specify the type of analysis to be performed using the `analysis_type` keyword. Setting it to `summary` will generate a caption (summary), `questions` will prepare answers (VQA) to a list of questions as set by the user, `summary_and_questions` will do both. Note that the desired analysis type needs to be set here in the initialization of the \n",
"detector object, and not when running the analysis for each image; the same holds true for the selected model."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_summary_detector = ammico.SummaryDetector(image_dict, analysis_type=\"summary\", model_type=\"base\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The implemented models are listed below.\n",
"\n",
"| input model name | model |\n",
"| ---------------- | ----- |\n",
"| base | BLIP image captioning base, ViT-B/16, pretrained on COCO dataset |\n",
"| large | BLIP image captioning large, ViT-L/16, pretrained on COCO dataset |\n",
"| vqa | BLIP base model fine-tuned on VQA v2.0 dataset |\n",
"| blip2_t5_pretrain_flant5xxl | BLIP2 pretrained on FlanT5<sub>XXL</sub> | \n",
"| blip2_t5_pretrain_flant5xl | BLIP2 pretrained on FlanT5<sub>XL</sub> | \n",
"| blip2_t5_caption_coco_flant5xl | BLIP2 pretrained on FlanT5<sub>XL</sub>, fine-tuned on COCO | \n",
"| blip2_opt_pretrain_opt2.7b | BLIP2 pretrained on OPT-2.7b |\n",
"| blip2_opt_pretrain_opt6.7b | BLIP2 pretrained on OPT-6.7b | \n",
"| blip2_opt_caption_coco_opt2.7b | BLIP2 pretrained on OPT-2.7b, fine-tuned on COCO | \n",
"| blip2_opt_caption_coco_opt6.7b | BLIP2 pretrained on OPT-6.7b, fine-tuned on COCO |\n",
"\n",
"For VQA, a list of questions needs to be passed when carrying out the analysis; these should be given as a list of strings."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"list_of_questions = [\n",
" \"How many persons on the picture?\",\n",
" \"Are there any politicians in the picture?\",\n",
" \"Does the picture show something from medicine?\",\n",
"]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Summarizing, the detector is run as"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"image_summary_vqa_detector = ammico.SummaryDetector(image_dict, analysis_type=\"summary_and_questions\", \n",
" model_type=\"base\")\n",
"for key in image_dict.keys():\n",
" image_dict[key] = image_summary_vqa_detector.analyse_image(image_dict[key], \n",
" list_of_questions = list_of_questions)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The output is given as a dictionary with the following keys and data types:\n",
"\n",
"| output key | output type | output value |\n",
"| ---------- | ----------- | ------------ |\n",
"| `const_image_summary` | `str` | when `analysis_type=\"summary\"` or `\"summary_and_questions\"`, constant image caption (does not change upon re-running the analysis for the same model) |\n",
"| `3_non-deterministic_summary` | `list[str]` | when `analysis_type=\"summary\"` or s`ummary_and_questions`, three different captions generated with different random seeds |\n",
"| *a user-defined input question* | `str` | when `analysis_type=\"questions\"` or `summary_and_questions`, the answer to the user-defined input question | \n",
"\n",
"## Detection of faces and facial expression analysis\n",
"Faces and facial expressions are detected and analyzed using the `EmotionDetector` class from the `faces` module. Initially, it is detected if faces are present on the image using RetinaFace, followed by analysis if face masks are worn (Face-Mask-Detection). The detection of age, gender, race, and emotions is carried out with deepface.\n",
"\n",
"<img src=\"../_static/emotion_detector.png\" width=\"800\" />\n",
"\n",
"Depending on the features found on the image, the face detection module returns a different analysis content: If no faces are found on the image, all further steps are skipped and the result `\"face\": \"No\", \"multiple_faces\": \"No\", \"no_faces\": 0, \"wears_mask\": [\"No\"], \"age\": [None], \"gender\": [None], \"race\": [None], \"emotion\": [None], \"emotion (category)\": [None]` is returned. If one or several faces are found, up to three faces are analyzed if they are partially concealed by a face mask. If yes, only age and gender are detected; if no, also race, emotion, and dominant emotion are detected. In case of the latter, the output could look like this: `\"face\": \"Yes\", \"multiple_faces\": \"Yes\", \"no_faces\": 2, \"wears_mask\": [\"No\", \"No\"], \"age\": [27, 28], \"gender\": [\"Man\", \"Man\"], \"race\": [\"asian\", None], \"emotion\": [\"angry\", \"neutral\"], \"emotion (category)\": [\"Negative\", \"Neutral\"]`, where for the two faces that are detected (given by `no_faces`), some of the values are returned as a list with the first item for the first (largest) face and the second item for the second (smaller) face (for example, `\"emotion\"` returns a list `[\"angry\", \"neutral\"]` signifying the first face expressing anger, and the second face having a neutral expression).\n",
"\n",
"The emotion detection reports the seven facial expressions angry, fear, neutral, sad, disgust, happy and surprise. These emotions are assigned based on the returned confidence of the model (between 0 and 1), with a high confidence signifying a high likelihood of the detected emotion being correct. Emotion recognition is not an easy task, even for a human; therefore, we have added a keyword `emotion_threshold` signifying the % value above which an emotion is counted as being detected. The default is set to 50%, so that a confidence above 0.5 results in an emotion being assigned. If the confidence is lower, no emotion is assigned. \n",
"\n",
"From the seven facial expressions, an overall dominating emotion category is identified: negative, positive, or neutral emotion. These are defined with the facial expressions angry, disgust, fear and sad for the negative category, happy for the positive category, and surprise and neutral for the neutral category.\n",
"\n",
"A similar threshold as for the emotion recognition is set for the race detection, `race_threshold`, with the default set to 50% so that a confidence for the race above 0.5 only will return a value in the analysis. \n",
"\n",
"Summarizing, the face detection is carried out using the following method call and keywords, where `emotion_threshold` and \n",
"`race_threshold` are optional:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.EmotionDetector(image_dict[key], emotion_threshold=50, race_threshold=50).analyse_image()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The thresholds can be adapted interactively in the notebook interface and the optimal value can then be used in a subsequent analysis of the whole data set.\n",
"\n",
"The output keys that are generated are\n",
"\n",
"| output key | output type | output value |\n",
"| ---------- | ----------- | ------------ |\n",
"| `face` | `str` | if a face is detected |\n",
"| `multiple_faces` | `str` | if multiple faces are detected |\n",
"| `no_faces` | `int` | the number of detected faces |\n",
"| `wears_mask` | `list[str]` | if each of the detected faces wears a face covering, up to three faces |\n",
"| `age` | `list[int]` | the detected age, up to three faces |\n",
"| `gender` | `list[str]` | the detected gender, up to three faces |\n",
"| `race` | `list[str]` | the detected race, up to three faces, if above the confidence threshold |\n",
"| `emotion` | `list[str]` | the detected emotion, up to three faces, if above the confidence threshold |\n",
"| `emotion (category)` | `list[str]` | the detected emotion category (positive, negative, or neutral), up to three faces, if above the confidence threshold |"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Further detector modules\n",
"Further detector modules exist, such as `ColorDetector` and `MultimodalSearch`, also it is possible to carry out a topic analysis on the text data, as well as crop social media posts automatically. These are more experimental features and have their own demonstration notebooks."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "ammico",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.18"
}
},
"nbformat": 4,
"nbformat_minor": 2
}

Просмотреть файл

@ -4,7 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"# Color analysis of pictures\n",
"# Color Detector\n",
"\n",
"\n",
"\n",
@ -64,28 +64,12 @@
"source": [
"# Here you need to provide the path to your google drive folder\n",
"# or local folder containing the images\n",
"images = mutils.find_files(\n",
" path=\"/content/drive/MyDrive/misinformation-data/\",\n",
"image_dict = mutils.find_files(\n",
" path=\"data/\",\n",
" limit=10,\n",
")\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We need to initialize the main dictionary that contains all information for the images and is updated through each subsequent analysis:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"mydict = mutils.initialize_dict(images)"
]
},
{
"cell_type": "markdown",
"metadata": {},
@ -100,7 +84,7 @@
"metadata": {},
"outputs": [],
"source": [
"analysis_explorer = mdisplay.AnalysisExplorer(mydict, identify=\"colors\")\n",
"analysis_explorer = mdisplay.AnalysisExplorer(image_dict)\n",
"analysis_explorer.run_server(port = 8057)"
]
},
@ -117,8 +101,8 @@
"metadata": {},
"outputs": [],
"source": [
"for key in mydict.keys():\n",
" mydict[key] = ammico.colors.ColorDetector(mydict[key]).analyse_image()"
"for key in image_dict.keys():\n",
" image_dict[key] = ammico.colors.ColorDetector(image_dict[key]).analyse_image()"
]
},
{
@ -134,8 +118,7 @@
"metadata": {},
"outputs": [],
"source": [
"outdict = mutils.append_data_to_dict(mydict)\n",
"df = mutils.dump_df(outdict)"
"image_df = ammico.get_dataframe(image_dict)"
]
},
{
@ -151,7 +134,7 @@
"metadata": {},
"outputs": [],
"source": [
"df.head(10)"
"image_df.head(10)"
]
},
{
@ -167,7 +150,7 @@
"metadata": {},
"outputs": [],
"source": [
"df.to_csv(\"/content/drive/MyDrive/misinformation-data/data_out.csv\")"
"image_df.to_csv(\"data_out.csv\")"
]
}
],

Просмотреть файл

@ -6,7 +6,7 @@
"id": "b25986d7",
"metadata": {},
"source": [
"# Crop posts from social media posts images"
"# Crop posts module"
]
},
{
@ -82,14 +82,14 @@
"# load ref view for cropping the same type social media posts images.\n",
"# substitute the below paths for your samples\n",
"path_ref = pkg / \"data\" / \"ref\" / \"ref-00.png\"\n",
"ref_view = cv2.imread(path_ref)\n",
"ref_view = cv2.imread(path_ref.as_posix())\n",
"RGB_ref_view = cv2.cvtColor(ref_view, cv2.COLOR_BGR2RGB)\n",
"plt.figure(figsize=(10, 15))\n",
"plt.imshow(RGB_ref_view)\n",
"plt.show()\n",
"\n",
"path_post = pkg / \"data\" / \"test-crop-image.png\"\n",
"view = cv2.imread(path_post)\n",
"view = cv2.imread(path_post.as_posix())\n",
"RGB_view = cv2.cvtColor(view, cv2.COLOR_BGR2RGB)\n",
"plt.figure(figsize=(10, 15))\n",
"plt.imshow(RGB_view)\n",
@ -139,12 +139,12 @@
"outputs": [],
"source": [
"\n",
"crop_dir = \"../ammico/data/\"\n",
"ref_dir = \"../ammico/data/ref\"\n",
"crop_dir = \"data/\"\n",
"ref_dir = pkg / \"data\" / \"ref\" \n",
"save_crop_dir = \"data/crop/\"\n",
"\n",
"files = utils.find_files(path=crop_dir,limit=10,)\n",
"ref_files = utils.find_files(path=ref_dir, limit=100)\n",
"ref_files = utils.find_files(path=ref_dir.as_posix(), limit=100)\n",
"\n",
"crpo.crop_media_posts(files, ref_files, save_crop_dir, plt_match=True, plt_crop=False, plt_image=False)\n",
"print(\"Batch cropping images done\")"

Просмотреть файл

@ -1,237 +0,0 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "d2c4d40d-8aca-4024-8d19-a65c4efe825d",
"metadata": {},
"source": [
"# Facial Expression recognition with DeepFace"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "51f8888b-d1a3-4b85-a596-95c0993fa192",
"metadata": {},
"source": [
"Facial expressions can be detected using [DeepFace](https://github.com/serengil/deepface) and [RetinaFace](https://github.com/serengil/retinaface).\n",
"\n",
"The first cell is only run on google colab and installs the [ammico](https://github.com/ssciwr/AMMICO) package.\n",
"\n",
"After that, we can import `ammico` and read in the files given a folder path."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "50c1c1c7",
"metadata": {},
"outputs": [],
"source": [
"# if running on google colab\n",
"# flake8-noqa-cell\n",
"import os\n",
"\n",
"if \"google.colab\" in str(get_ipython()):\n",
" # update python version\n",
" # install setuptools\n",
" # %pip install setuptools==61 -qqq\n",
" # install ammico\n",
" %pip install git+https://github.com/ssciwr/ammico.git -qqq\n",
" # mount google drive for data and API key\n",
" from google.colab import drive\n",
"\n",
" drive.mount(\"/content/drive\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b21e52a5-d379-42db-aae6-f2ab9ed9a369",
"metadata": {},
"outputs": [],
"source": [
"import ammico\n",
"from ammico import utils as mutils\n",
"from ammico import display as mdisplay"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "a2bd2153",
"metadata": {},
"source": [
"We select a subset of image files to try facial expression detection on, see the `limit` keyword. The `find_files` function finds image files within a given directory:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "afe7e638-f09d-47e7-9295-1c374bd64c53",
"metadata": {},
"outputs": [],
"source": [
"# Here you need to provide the path to your google drive folder\n",
"# or local folder containing the images\n",
"images = mutils.find_files(\n",
" path=\"data/\",\n",
" limit=10,\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "705e7328",
"metadata": {},
"source": [
"We need to initialize the main dictionary that contains all information for the images and is updated through each subsequent analysis:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b37c0c91",
"metadata": {},
"outputs": [],
"source": [
"mydict = mutils.initialize_dict(images)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "a9372561",
"metadata": {},
"source": [
"To check the analysis, you can inspect the analyzed elements here. Loading the results takes a moment, so please be patient. If you are sure of what you are doing, you can skip this and directly export a csv file in the step below.\n",
"Here, we display the face recognition results provided by the DeepFace and RetinaFace libraries. Click on the tabs to see the results in the right sidebar. You may need to increment the `port` number if you are already running several notebook instances on the same server."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "992499ed-33f1-4425-ad5d-738cf565d175",
"metadata": {},
"outputs": [],
"source": [
"analysis_explorer = mdisplay.AnalysisExplorer(mydict, identify=\"faces\")\n",
"analysis_explorer.run_server(port = 8050)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "6f974341",
"metadata": {},
"source": [
"Instead of inspecting each of the images, you can also directly carry out the analysis and export the result into a csv. This may take a while depending on how many images you have loaded."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "6f97c7d0",
"metadata": {},
"outputs": [],
"source": [
"for key in mydict.keys():\n",
" mydict[key] = ammico.faces.EmotionDetector(mydict[key]).analyse_image()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "174357b1",
"metadata": {},
"source": [
"These steps are required to convert the dictionary of dictionarys into a dictionary with lists, that can be converted into a pandas dataframe and exported to a csv file."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "604bd257",
"metadata": {},
"outputs": [],
"source": [
"outdict = mutils.append_data_to_dict(mydict)\n",
"df = mutils.dump_df(outdict)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "8373d9f8",
"metadata": {},
"source": [
"Check the dataframe:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "aa4b518a",
"metadata": {},
"outputs": [],
"source": [
"df.head(10)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "579cd59f",
"metadata": {},
"source": [
"Write the csv file - here you should provide a file path and file name for the csv file to be written."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4618decb",
"metadata": {},
"outputs": [],
"source": [
"df.to_csv(\"data_out.csv\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "b1a80023",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
},
"vscode": {
"interpreter": {
"hash": "da98320027a74839c7141b42ef24e2d47d628ba1f51115c13da5d8b45a372ec2"
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}

Просмотреть файл

@ -6,7 +6,7 @@
"id": "22df2297-0629-45aa-b88c-6c61f1544db6",
"metadata": {},
"source": [
"# Image Multimodal Search"
"# Multimodal search module"
]
},
{
@ -67,7 +67,7 @@
},
"outputs": [],
"source": [
"images = mutils.find_files(\n",
"mydict = mutils.find_files(\n",
" path=\"data/\",\n",
" limit=10,\n",
")"
@ -79,28 +79,6 @@
"id": "a08bd3a9-e954-4a0e-ad64-6817abd3a25a",
"metadata": {},
"outputs": [],
"source": [
"images"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "adf3db21-1f8b-4d44-bbef-ef0acf4623a0",
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"mydict = mutils.initialize_dict(images)"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "4c091f95-07cf-42c3-82c8-5f3a3c5929f8",
"metadata": {},
"outputs": [],
"source": [
"mydict"
]
@ -481,8 +459,7 @@
},
"outputs": [],
"source": [
"outdict = mutils.append_data_to_dict(mydict)\n",
"df = mutils.dump_df(outdict)"
"df = mutils.get_dataframe(mydict)"
]
},
{

Просмотреть файл

@ -1,352 +0,0 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"# Image summary and visual question answering"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"This notebooks shows how to generate image captions and use the visual question answering with [LAVIS](https://github.com/salesforce/LAVIS). \n",
"\n",
"The first cell is only run on google colab and installs the [ammico](https://github.com/ssciwr/AMMICO) package.\n",
"\n",
"After that, we can import `ammico` and read in the files given a folder path."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# if running on google colab\n",
"# flake8-noqa-cell\n",
"import os\n",
"\n",
"if \"google.colab\" in str(get_ipython()):\n",
" # update python version\n",
" # install setuptools\n",
" # %pip install setuptools==61 -qqq\n",
" # install ammico\n",
" %pip install git+https://github.com/ssciwr/ammico.git -qqq\n",
" # mount google drive for data and API key\n",
" from google.colab import drive\n",
"\n",
" drive.mount(\"/content/drive\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"import ammico\n",
"from ammico import utils as mutils\n",
"from ammico import display as mdisplay\n",
"import ammico.summary as sm"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"# Here you need to provide the path to your google drive folder\n",
"# or local folder containing the images\n",
"images = mutils.find_files(\n",
" path=\"data/\",\n",
" limit=10,\n",
")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"mydict = mutils.initialize_dict(images)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create captions for images and directly write to csv"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Here you can choose between two models: \"base\" or \"large\". This will generate the caption for each image and directly put the results in a dataframe. This dataframe can be exported as a csv file.\n",
"\n",
"The results are written into the columns `const_image_summary` - this will always be the same result (as always the same seed will be used). The column `3_non-deterministic_summary` displays three different answers generated with different seeds, these are most likely different when you run the analysis again."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"obj = sm.SummaryDetector(mydict)\n",
"summary_model, summary_vis_processors = obj.load_model(model_type=\"base\")\n",
"# summary_model, summary_vis_processors = mutils.load_model(\"large\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"for key in mydict:\n",
" mydict[key] = sm.SummaryDetector(mydict[key]).analyse_image(\n",
" summary_model=summary_model, summary_vis_processors=summary_vis_processors\n",
" )"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {
"tags": []
},
"source": [
"Convert the dictionary of dictionarys into a dictionary with lists:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"outdict = mutils.append_data_to_dict(mydict)\n",
"df = mutils.dump_df(outdict)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Check the dataframe:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"df.head(10)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Write the csv file:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df.to_csv(\"data_out.csv\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Manually inspect the summaries\n",
"\n",
"To check the analysis, you can inspect the analyzed elements here. Loading the results takes a moment, so please be patient. If you are sure of what you are doing.\n",
"\n",
"`const_image_summary` - the permanent summarys, which does not change from run to run (analyse_image).\n",
"\n",
"`3_non-deterministic_summary` - 3 different summarys examples that change from run to run (analyse_image). "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"tags": []
},
"outputs": [],
"source": [
"analysis_explorer = mdisplay.AnalysisExplorer(mydict, identify=\"summary\")\n",
"analysis_explorer.run_server(port=8055)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Generate answers to free-form questions about images written in natural language. "
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Set the list of questions as a list of strings:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"list_of_questions = [\n",
" \"How many persons on the picture?\",\n",
" \"Are there any politicians in the picture?\",\n",
" \"Does the picture show something from medicine?\",\n",
"]"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"Explore the analysis using the interface:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"analysis_explorer = mdisplay.AnalysisExplorer(mydict, identify=\"summary\")\n",
"analysis_explorer.run_server(port=8055)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Or directly analyze for further processing\n",
"Instead of inspecting each of the images, you can also directly carry out the analysis and export the result into a csv. This may take a while depending on how many images you have loaded."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for key in mydict:\n",
" mydict[key] = sm.SummaryDetector(mydict[key]).analyse_questions(list_of_questions)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"## Convert to dataframe and write csv\n",
"These steps are required to convert the dictionary of dictionarys into a dictionary with lists, that can be converted into a pandas dataframe and exported to a csv file."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"outdict2 = mutils.append_data_to_dict(mydict)\n",
"df2 = mutils.dump_df(outdict2)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df2.head(10)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"df2.to_csv(\"data_out2.csv\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
},
"vscode": {
"interpreter": {
"hash": "f1142466f556ab37fe2d38e2897a16796906208adb09fea90ba58bdf8a56f0ba"
}
}
},
"nbformat": 4,
"nbformat_minor": 4
}

Просмотреть файл

@ -1,413 +0,0 @@
{
"cells": [
{
"attachments": {},
"cell_type": "markdown",
"id": "dcaa3da1",
"metadata": {},
"source": [
"# Notebook for text extraction on image\n",
"\n",
"The text extraction and analysis is carried out using a variety of tools: \n",
"\n",
"1. Text extraction from the image using [google-cloud-vision](https://cloud.google.com/vision) \n",
"1. Language detection of the extracted text using [Googletrans](https://py-googletrans.readthedocs.io/en/latest/) \n",
"1. Translation into English or other languages using [Googletrans](https://py-googletrans.readthedocs.io/en/latest/) \n",
"1. Cleaning of the text using [spacy](https://spacy.io/) \n",
"1. Spell-check using [TextBlob](https://textblob.readthedocs.io/en/dev/index.html) \n",
"1. Subjectivity analysis using [TextBlob](https://textblob.readthedocs.io/en/dev/index.html) \n",
"1. Text summarization using [transformers](https://huggingface.co/docs/transformers/index) pipelines\n",
"1. Sentiment analysis using [transformers](https://huggingface.co/docs/transformers/index) pipelines \n",
"1. Named entity recognition using [transformers](https://huggingface.co/docs/transformers/index) pipelines \n",
"1. Topic analysis using [BERTopic](https://github.com/MaartenGr/BERTopic) \n",
"\n",
"The first cell is only run on google colab and installs the [ammico](https://github.com/ssciwr/AMMICO) package.\n",
"\n",
"After that, we can import `ammico` and read in the files given a folder path."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "f43f327c",
"metadata": {},
"outputs": [],
"source": [
"# if running on google colab\n",
"# flake8-noqa-cell\n",
"import os\n",
"\n",
"if \"google.colab\" in str(get_ipython()):\n",
" # update python version\n",
" # install setuptools\n",
" # %pip install setuptools==61 -qqq\n",
" # install ammico\n",
" %pip install git+https://github.com/ssciwr/ammico.git -qqq\n",
" # mount google drive for data and API key\n",
" from google.colab import drive\n",
"\n",
" drive.mount(\"/content/drive\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "cf362e60",
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import ammico\n",
"from ammico import utils as mutils\n",
"from ammico import display as mdisplay"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "fddba721",
"metadata": {},
"source": [
"We select a subset of image files to try the text extraction on, see the `limit` keyword. The `find_files` function finds image files within a given directory: "
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "27675810",
"metadata": {},
"outputs": [],
"source": [
"# Here you need to provide the path to your google drive folder\n",
"# or local folder containing the images\n",
"images = mutils.find_files(\n",
" path=\"data/\",\n",
" limit=10,\n",
")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "3a7dfe11",
"metadata": {},
"source": [
"We need to initialize the main dictionary that contains all information for the images and is updated through each subsequent analysis:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "8b32409f",
"metadata": {},
"outputs": [],
"source": [
"mydict = mutils.initialize_dict(images)"
]
},
{
"cell_type": "markdown",
"id": "7b8b929f",
"metadata": {},
"source": [
"## Google cloud vision API\n",
"\n",
"For this you need an API key and have the app activated in your google console. The first 1000 images per month are free (July 2022)."
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "cbf74c0b-52fe-4fb8-b617-f18611e8f986",
"metadata": {},
"source": [
"```\n",
"os.environ[\n",
" \"GOOGLE_APPLICATION_CREDENTIALS\"\n",
"] = \"your-credentials.json\"\n",
"```"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "0891b795-c7fe-454c-a45d-45fadf788142",
"metadata": {},
"source": [
"## Inspect the elements per image\n",
"To check the analysis, you can inspect the analyzed elements here. Loading the results takes a moment, so please be patient. If you are sure of what you are doing, you can skip this and directly export a csv file in the step below.\n",
"Here, we display the text extraction and translation results provided by the above libraries. Click on the tabs to see the results in the right sidebar. You may need to increment the `port` number if you are already running several notebook instances on the same server."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7c6ecc88",
"metadata": {},
"outputs": [],
"source": [
"analysis_explorer = mdisplay.AnalysisExplorer(mydict, identify=\"text-on-image\")\n",
"analysis_explorer.run_server(port=8054)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "9c3e72b5-0e57-4019-b45e-3e36a74e7f52",
"metadata": {},
"source": [
"## Or directly analyze for further processing\n",
"Instead of inspecting each of the images, you can also directly carry out the analysis and export the result into a csv. This may take a while depending on how many images you have loaded. Set the keyword `analyse_text` to `True` if you want the text to be analyzed (spell check, subjectivity, text summary, sentiment, NER)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "365c78b1-7ff4-4213-86fa-6a0a2d05198f",
"metadata": {},
"outputs": [],
"source": [
"for key in mydict:\n",
" mydict[key] = ammico.text.TextDetector(\n",
" mydict[key], analyse_text=True\n",
" ).analyse_image()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "3c063eda",
"metadata": {},
"source": [
"## Convert to dataframe and write csv\n",
"These steps are required to convert the dictionary of dictionarys into a dictionary with lists, that can be converted into a pandas dataframe and exported to a csv file."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5709c2cd",
"metadata": {},
"outputs": [],
"source": [
"outdict = mutils.append_data_to_dict(mydict)\n",
"df = mutils.dump_df(outdict)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "ae182eb7",
"metadata": {},
"source": [
"Check the dataframe:"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "c4f05637",
"metadata": {},
"outputs": [],
"source": [
"df.head(10)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "eedf1e47",
"metadata": {},
"source": [
"Write the csv file - here you should provide a file path and file name for the csv file to be written."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "bf6c9ddb",
"metadata": {},
"outputs": [],
"source": [
"# Write the csv\n",
"df.to_csv(\"./data_out.csv\")"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "4bc8ac0a",
"metadata": {},
"source": [
"## Topic analysis\n",
"The topic analysis is carried out using [BERTopic](https://maartengr.github.io/BERTopic/index.html) using an embedded model through a [spaCy](https://spacy.io/) pipeline."
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "4931941b",
"metadata": {},
"source": [
"BERTopic takes a list of strings as input. The more items in the list, the better for the topic modeling. If the below returns an error for `analyse_topic()`, the reason can be that your dataset is too small.\n",
"\n",
"You can pass which dataframe entry you would like to have analyzed. The default is `text_english`, but you could for example also select `text_summary` or `text_english_correct` setting the keyword `analyze_text` as so:\n",
"\n",
"`ammico.text.PostprocessText(mydict=mydict, analyze_text=\"text_summary\").analyse_topic()`\n",
"\n",
"### Option 1: Use the dictionary as obtained from the above analysis."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "a3450a61",
"metadata": {},
"outputs": [],
"source": [
"# make a list of all the text_english entries per analysed image from the mydict variable as above\n",
"topic_model, topic_df, most_frequent_topics = ammico.text.PostprocessText(\n",
" mydict=mydict\n",
").analyse_topic()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "95667342",
"metadata": {},
"source": [
"### Option 2: Read in a csv\n",
"Not to analyse too many images on google Cloud Vision, use the csv output to obtain the text (when rerunning already analysed images)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "5530e436",
"metadata": {},
"outputs": [],
"source": [
"input_file_path = \"data_out.csv\"\n",
"topic_model, topic_df, most_frequent_topics = ammico.text.PostprocessText(\n",
" use_csv=True, csv_path=input_file_path\n",
").analyse_topic(return_topics=10)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "0b6ef6d7",
"metadata": {},
"source": [
"### Access frequent topics\n",
"A topic of `-1` stands for an outlier and should be ignored. Topic count is the number of occurence of that topic. The output is structured from most frequent to least frequent topic."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "43288cda-61bb-4ff1-a209-dcfcc4916b1f",
"metadata": {},
"outputs": [],
"source": [
"print(topic_df)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "b3316770",
"metadata": {},
"source": [
"### Get information for specific topic\n",
"The most frequent topics can be accessed through `most_frequent_topics` with the most occuring topics first in the list."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "db14fe03",
"metadata": {},
"outputs": [],
"source": [
"for topic in most_frequent_topics:\n",
" print(\"Topic:\", topic)"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "d10f701e",
"metadata": {},
"source": [
"### Topic visualization\n",
"The topics can also be visualized. Careful: This only works if there is sufficient data (quantity and quality)."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "2331afe6",
"metadata": {},
"outputs": [],
"source": [
"topic_model.visualize_topics()"
]
},
{
"attachments": {},
"cell_type": "markdown",
"id": "f4eaf353",
"metadata": {},
"source": [
"### Save the model\n",
"The model can be saved for future use."
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "e5e8377c",
"metadata": {},
"outputs": [],
"source": [
"topic_model.save(\"misinfo_posts\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"id": "7c94edb9",
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.16"
},
"vscode": {
"interpreter": {
"hash": "da98320027a74839c7141b42ef24e2d47d628ba1f51115c13da5d8b45a372ec2"
}
}
},
"nbformat": 4,
"nbformat_minor": 5
}