add_model_resnet18 #31
+2
-1
@@ -57,8 +57,9 @@ RUN mkdir -p /home/app && \
|
||||
# add code while changing ownership
|
||||
WORKDIR $APP_HOME
|
||||
COPY --chown=app:app ./src ./src
|
||||
COPY --chown=app:app ./core ./core
|
||||
|
||||
# change to the app user
|
||||
USER app
|
||||
|
||||
ENTRYPOINT [ "gunicorn", "src.main:server", "-b", "0.0.0.0:8050" ]
|
||||
ENTRYPOINT [ "gunicorn", "src.main:server", "-b", "0.0.0.0:8050" ]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Database module content."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .classes import Dataset
|
||||
from .classes import NoDocumentFoundException
|
||||
from .classes import VisualCommunication
|
||||
from .utils import connect
|
||||
from .utils.count_documents import count_documents
|
||||
from .utils.get_visual_communication import get_visual_communication
|
||||
from .utils.list_names import list_names
|
||||
from .utils.upsert_annotation import upsert_annotation
|
||||
from .utils.upsert_prediction import upsert_prediction
|
||||
from .utils.upsert_visual_communication import upsert_visual_communication
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
"""Database classes module content."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .dataset import Dataset
|
||||
from .exceptions import NoDocumentFoundException
|
||||
from .visual_communication import VisualCommunication
|
||||
Executable
+71
@@ -0,0 +1,71 @@
|
||||
"""Definition of database Dataset class."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import random
|
||||
from datetime import datetime
|
||||
from datetime import UTC
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import Field
|
||||
from pymongo.collection import Collection
|
||||
|
||||
|
||||
class Dataset(BaseModel):
|
||||
"""Database Dataset model."""
|
||||
create_time: datetime = Field(default_factory=lambda: datetime.now(UTC))
|
||||
train_names: list[str]
|
||||
test_names: list[str]
|
||||
validation_names: list[str]
|
||||
|
||||
@classmethod
|
||||
def fraction_map(cls) -> dict[str, float]:
|
||||
"""Dict with train, test and validation fractions."""
|
||||
# define map
|
||||
split_map = {
|
||||
'train': 0.7,
|
||||
'test': 0.2,
|
||||
'validation': 0.1,
|
||||
}
|
||||
# sanity check
|
||||
assert sum(split_map.values()) == 1.0
|
||||
return split_map
|
||||
|
||||
@classmethod
|
||||
def new_from_name_list(
|
||||
cls,
|
||||
name_list: list[str],
|
||||
) -> Dataset:
|
||||
"""Generate new dataset from list of filenames."""
|
||||
# calculate split fractions
|
||||
fraction_map = cls.fraction_map()
|
||||
num_total = len(name_list)
|
||||
num_validation = round(num_total * fraction_map['validation'])
|
||||
num_test = round(num_total * fraction_map['test'])
|
||||
# split data
|
||||
validation_name_list = random.choices(name_list, k=num_validation)
|
||||
name_list = [
|
||||
name for name in name_list if name not in validation_name_list
|
||||
]
|
||||
test_name_list = random.choices(name_list, k=num_test)
|
||||
train_name_list = [
|
||||
name for name in name_list if name not in test_name_list
|
||||
]
|
||||
# instantiate object
|
||||
dataset = Dataset(
|
||||
train_names=train_name_list,
|
||||
test_names=test_name_list,
|
||||
validation_names=validation_name_list,
|
||||
)
|
||||
logging.debug('finished')
|
||||
return dataset
|
||||
|
||||
def save(
|
||||
self,
|
||||
collection: Collection,
|
||||
) -> None:
|
||||
"""Save dataset to database."""
|
||||
res = collection.insert_one(
|
||||
document=self.model_dump(),
|
||||
)
|
||||
logging.debug('inserted document: %s', res)
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
"""Definition of database exception."""
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class NoDocumentFoundException(Exception):
|
||||
"""Database exception for when no documents are found."""
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
"""Definition of VisualCommunication model."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from base64 import b64decode
|
||||
from base64 import b64encode
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
from pydantic import BaseModel
|
||||
from pydantic import field_serializer
|
||||
from pydantic import field_validator
|
||||
|
||||
from core.dto import ModelData
|
||||
|
||||
|
||||
class VisualCommunication(BaseModel):
|
||||
"""Visual communication model."""
|
||||
|
||||
name: str
|
||||
image: Image.Image
|
||||
annotation: ModelData | None = None
|
||||
prediction: ModelData | None = None
|
||||
|
||||
class Config:
|
||||
"""BaseModel configuration."""
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
@classmethod
|
||||
def classname(cls) -> str:
|
||||
"""Return classname."""
|
||||
return cls.__name__
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, path: Path) -> VisualCommunication:
|
||||
"""Instantiate from file."""
|
||||
name = path.stem
|
||||
image = Image.open(path)
|
||||
image.load()
|
||||
return VisualCommunication(name=name, image=image)
|
||||
|
||||
@classmethod
|
||||
def decode_image(cls, content: str) -> Image.Image:
|
||||
"""Extract image from webencoded content."""
|
||||
_, content_data = content.split(',')
|
||||
return Image.open(BytesIO(b64decode(content_data)))
|
||||
|
||||
@field_serializer('image')
|
||||
@classmethod
|
||||
def serialize_image(cls, image: Image.Image) -> bytes: # type: ignore
|
||||
"""Convert image to bytes for storage in database."""
|
||||
buffer = BytesIO()
|
||||
image.save(buffer, format='JPEG')
|
||||
return buffer.getvalue()
|
||||
|
||||
@field_validator('image', mode='before')
|
||||
@classmethod
|
||||
def convert_to_image(
|
||||
cls,
|
||||
image: Image.Image | BytesIO | bytes,
|
||||
) -> Image.Image:
|
||||
"""Convert bytes input from database into image."""
|
||||
if isinstance(image, bytes):
|
||||
image = BytesIO(image)
|
||||
if isinstance(image, BytesIO):
|
||||
image = Image.open(image)
|
||||
return image
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.classname()}(name='{self.name}')"
|
||||
|
||||
def webencoded_image(self) -> str:
|
||||
"""Convert image to be displayed on webpage."""
|
||||
# convert images to bytes string
|
||||
buffer = BytesIO()
|
||||
self.image.save(buffer, format='png')
|
||||
img_enc = b64encode(buffer.getvalue()).decode('utf-8')
|
||||
return f"data:image/png;base64, {img_enc}"
|
||||
|
||||
def generate_random_prediction(self, force: bool = False) -> None:
|
||||
"""Generate random prediction values."""
|
||||
if not force and self.prediction is not None:
|
||||
logging.warning('set force=True to overwrite existing values.')
|
||||
self.prediction = ModelData.from_random()
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
"""Database utils module content."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .connect import connect
|
||||
@@ -0,0 +1,33 @@
|
||||
"""
|
||||
Definition of function to connect to database
|
||||
using environment variables.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import os
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from pymongo import MongoClient
|
||||
|
||||
|
||||
def connect():
|
||||
"""Connect to MongoDB using env vars."""
|
||||
# load env vars
|
||||
load_dotenv()
|
||||
necessary_env_vars = [
|
||||
'MONGO_HOST',
|
||||
'MONGO_DB',
|
||||
'MONGO_COLLECTION',
|
||||
]
|
||||
for env_var in necessary_env_vars:
|
||||
assert env_var in os.environ, f"{env_var} not found"
|
||||
# connect to database
|
||||
client = MongoClient(os.getenv('MONGO_HOST'))
|
||||
db = client[os.getenv('MONGO_DB')]
|
||||
# extract collection
|
||||
collection = db[os.getenv('MONGO_COLLECTION')]
|
||||
# set unique index on "name"
|
||||
collection.create_index('name', unique=True)
|
||||
logging.debug('finished')
|
||||
return collection, db, client
|
||||
Executable
+21
@@ -0,0 +1,21 @@
|
||||
"""Definition of function to count documents in database."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
|
||||
def count_documents(
|
||||
collection: Collection,
|
||||
only_with_annotation: bool = False,
|
||||
) -> int:
|
||||
"""
|
||||
Get the total number of documents
|
||||
in database that matches the filters.
|
||||
"""
|
||||
assert isinstance(collection, Collection)
|
||||
assert isinstance(only_with_annotation, bool)
|
||||
# build query
|
||||
query = {}
|
||||
if only_with_annotation:
|
||||
query['annotation'] = {'$ne': None}
|
||||
return collection.count_documents(filter=query)
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
"""Definition of function to get visual communication from database."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.database import NoDocumentFoundException
|
||||
from core.database import VisualCommunication
|
||||
|
||||
|
||||
def get_visual_communication(
|
||||
collection: Collection,
|
||||
with_annotation: bool = False,
|
||||
) -> VisualCommunication:
|
||||
"""Get a random visual communication from the database."""
|
||||
query = {}
|
||||
if with_annotation:
|
||||
query['annotation'] = {'$ne': None}
|
||||
else:
|
||||
query['annotation'] = {'$eq': None}
|
||||
data = collection.aggregate(
|
||||
pipeline=[
|
||||
{
|
||||
'$match': query, # find using filters
|
||||
},
|
||||
{
|
||||
'$sample': {
|
||||
'size': 1, # get one random
|
||||
},
|
||||
},
|
||||
],
|
||||
)
|
||||
data_list = list(data) # read data from cursor object
|
||||
if len(data_list) == 0:
|
||||
raise NoDocumentFoundException()
|
||||
vis_com = VisualCommunication.model_validate(data_list[0])
|
||||
logging.debug('finished')
|
||||
return vis_com
|
||||
Executable
+31
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Definition of function to list names
|
||||
of all visual communication documents in database.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
|
||||
def list_names(
|
||||
collection: Collection,
|
||||
only_with_annotation: bool = True,
|
||||
) -> list[str]:
|
||||
"""List the names of entries that match the filters."""
|
||||
assert isinstance(collection, Collection)
|
||||
assert isinstance(only_with_annotation, bool)
|
||||
# build query
|
||||
query = {}
|
||||
if only_with_annotation:
|
||||
query['annotation'] = {'$ne': None}
|
||||
# execute query
|
||||
res_list = collection.find(
|
||||
filter=query,
|
||||
projection={
|
||||
'_id': False,
|
||||
'name': True,
|
||||
},
|
||||
)
|
||||
# extract information
|
||||
name_list = [elem['name'] for elem in res_list]
|
||||
return name_list
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.dto import ModelData
|
||||
|
||||
|
||||
def upsert_annotation(
|
||||
collection: Collection,
|
||||
vis_com_name: str,
|
||||
annotations: ModelData,
|
||||
) -> None:
|
||||
"""Upserts annotation data in the database."""
|
||||
query = {
|
||||
'name': vis_com_name,
|
||||
}
|
||||
update = {
|
||||
'$set': {
|
||||
'annotation': annotations.model_dump(),
|
||||
},
|
||||
}
|
||||
res = collection.update_one(
|
||||
filter=query,
|
||||
update=update,
|
||||
upsert=True,
|
||||
)
|
||||
logging.info('upserted document: %s', res)
|
||||
logging.info('finished')
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.dto import ModelData
|
||||
|
||||
|
||||
def upsert_prediction(
|
||||
collection: Collection,
|
||||
vis_com_name: str,
|
||||
predictions: ModelData,
|
||||
) -> None:
|
||||
"""Upsert prediction data in the database."""
|
||||
query = {
|
||||
'name': vis_com_name,
|
||||
}
|
||||
update = {
|
||||
'$set': {
|
||||
'prediction': predictions.model_dump(),
|
||||
},
|
||||
}
|
||||
res = collection.update_one(
|
||||
filter=query,
|
||||
update=update,
|
||||
upsert=True,
|
||||
)
|
||||
logging.debug('upserted document: %s', res)
|
||||
logging.info('finished')
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from core.database import VisualCommunication
|
||||
|
||||
|
||||
def upsert_visual_communication(
|
||||
collection: Collection,
|
||||
visual_communication_list: list[VisualCommunication],
|
||||
) -> bool:
|
||||
"""
|
||||
Upsert VisualCommunication object in the database.
|
||||
Returns bool stating success.
|
||||
"""
|
||||
response = collection.insert_many(
|
||||
[
|
||||
vis_com.model_dump()
|
||||
for vis_com
|
||||
in visual_communication_list
|
||||
],
|
||||
)
|
||||
return response.acknowledged
|
||||
@@ -0,0 +1,15 @@
|
||||
"""Data transfer objects module content."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .angle import AngleData
|
||||
from .contact import ContactData
|
||||
from .distance import DistanceData
|
||||
from .framing import FramingData
|
||||
from .information_value import InformationValueData
|
||||
from .modality_color import ModalityColorData
|
||||
from .modality_depth import ModalityDepthData
|
||||
from .modality_lighting import ModalityLightingData
|
||||
from .model_data import ModelData
|
||||
from .point_of_view import PointOfViewData
|
||||
from .salience import SalienceData
|
||||
from .visual_syntax import VisualSyntaxData
|
||||
@@ -0,0 +1,11 @@
|
||||
"""Definition of Angle data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class AngleData(DataModel):
|
||||
"""Angle data model."""
|
||||
high: float
|
||||
eye_level: float
|
||||
low: float
|
||||
@@ -0,0 +1,11 @@
|
||||
"""Definition of ContactData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class ContactData(DataModel):
|
||||
"""ContactData data model."""
|
||||
|
||||
offer: float
|
||||
demand: float
|
||||
@@ -0,0 +1,67 @@
|
||||
"""Definition of DataModel base class."""
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
|
||||
from pydantic import BaseModel
|
||||
from pydantic import ValidationError
|
||||
|
||||
|
||||
class DataModel(BaseModel):
|
||||
"""DataModel base class."""
|
||||
|
||||
@classmethod
|
||||
def classname(cls) -> str:
|
||||
"""Return classname."""
|
||||
return cls.__name__
|
||||
|
||||
@classmethod
|
||||
def list_fields(cls) -> list[str]:
|
||||
"""List options that are stored as attributes."""
|
||||
return list(cls.model_fields.keys())
|
||||
|
||||
@classmethod
|
||||
def from_random(cls):
|
||||
"""Instantiate with random numbers."""
|
||||
kwargs = {field: random.random() for field in cls.list_fields()}
|
||||
return cls(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_choice(cls, option: str):
|
||||
"""Instantiate from choice."""
|
||||
if option is None:
|
||||
raise ValidationError()
|
||||
assert isinstance(option, str), 'option is not a string'
|
||||
allowed_options_list = cls.list_fields()
|
||||
assert option in allowed_options_list, \
|
||||
f"{option} is not among allowed fields {allowed_options_list}"
|
||||
kwargs = {field: 0 for field in cls.list_fields()}
|
||||
kwargs[option] = 1
|
||||
return cls(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_list(cls, data_list: list[float]):
|
||||
"""Instantiate from list of values."""
|
||||
kwargs = {key: val for key, val in zip(cls.list_fields(), data_list)}
|
||||
return cls(**kwargs)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
model_dict = self.model_dump()
|
||||
model_repr_str = f"{self.classname()}("
|
||||
model_repr_str += ', '.join([
|
||||
f"{field}={value:.3f}"
|
||||
for field, value
|
||||
in model_dict.items()
|
||||
])
|
||||
model_repr_str += ')'
|
||||
return model_repr_str
|
||||
|
||||
def highest_score_field(self) -> str:
|
||||
"""Return name of field with highest score."""
|
||||
model_dict = self.model_dump()
|
||||
return max(model_dict, key=lambda k: model_dict[k])
|
||||
|
||||
def highest_score_value(self) -> float:
|
||||
"""Return value of field with highest score."""
|
||||
model_dict = self.model_dump()
|
||||
return max(model_dict.values())
|
||||
@@ -0,0 +1,12 @@
|
||||
"""Definition of DistanceData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class DistanceData(DataModel):
|
||||
"""DistanceData data model."""
|
||||
|
||||
long: float
|
||||
medium: float
|
||||
close: float
|
||||
@@ -0,0 +1,13 @@
|
||||
"""Definition of FramingData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class FramingData(DataModel):
|
||||
"""FramingData data model."""
|
||||
|
||||
frame_lines: float
|
||||
empty_space: float
|
||||
colour_contrast: float
|
||||
form_contrast: float
|
||||
@@ -0,0 +1,12 @@
|
||||
"""Definition of InformationValueData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class InformationValueData(DataModel):
|
||||
"""InformationValueData data model."""
|
||||
|
||||
given_new: float
|
||||
ideal_real: float
|
||||
central_marginal: float
|
||||
@@ -0,0 +1,12 @@
|
||||
"""Definition of ModalityColorData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class ModalityColorData(DataModel):
|
||||
"""ModalityColorData data model."""
|
||||
|
||||
high: float
|
||||
medium: float
|
||||
low: float
|
||||
@@ -0,0 +1,12 @@
|
||||
"""Definition of ModalityDepthData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class ModalityDepthData(DataModel):
|
||||
"""ModalityDepthData data model."""
|
||||
|
||||
high: float
|
||||
medium: float
|
||||
low: float
|
||||
@@ -0,0 +1,12 @@
|
||||
"""Definition of ModalityLightingData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class ModalityLightingData(DataModel):
|
||||
"""ModalityLightingData data model."""
|
||||
|
||||
high: float
|
||||
medium: float
|
||||
low: float
|
||||
@@ -0,0 +1,82 @@
|
||||
"""Definition of ModelData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .angle import AngleData
|
||||
from .contact import ContactData
|
||||
from .data_model import DataModel
|
||||
from .distance import DistanceData
|
||||
from .framing import FramingData
|
||||
from .information_value import InformationValueData
|
||||
from .modality_color import ModalityColorData
|
||||
from .modality_depth import ModalityDepthData
|
||||
from .modality_lighting import ModalityLightingData
|
||||
from .point_of_view import PointOfViewData
|
||||
from .salience import SalienceData
|
||||
from .visual_syntax import VisualSyntaxData
|
||||
|
||||
|
||||
class ModelData(DataModel):
|
||||
"""ModelData model for data IO with combined ML model."""
|
||||
visual_syntax: VisualSyntaxData
|
||||
contact: ContactData
|
||||
angle: AngleData
|
||||
point_of_view: PointOfViewData
|
||||
distance: DistanceData
|
||||
modality_lighting: ModalityLightingData
|
||||
modality_color: ModalityColorData
|
||||
modality_depth: ModalityDepthData
|
||||
information_value: InformationValueData
|
||||
framing: FramingData
|
||||
salience: SalienceData
|
||||
|
||||
@classmethod
|
||||
def from_random(cls) -> ModelData:
|
||||
"""Instantiate with random numbers."""
|
||||
kwargs = {
|
||||
field: field_info.annotation.from_random() # type: ignore
|
||||
for field, field_info
|
||||
in cls.model_fields.items()
|
||||
}
|
||||
return cls(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_annotations(
|
||||
cls,
|
||||
visual_syntax: str,
|
||||
contact: str,
|
||||
angle: str,
|
||||
point_of_view: str,
|
||||
distance: str,
|
||||
modality_lighting: str,
|
||||
modality_color: str,
|
||||
modality_depth: str,
|
||||
information_value: str,
|
||||
framing: str,
|
||||
salience: str,
|
||||
) -> ModelData:
|
||||
"""Instantiate from annotation."""
|
||||
kwargs = {
|
||||
'visual_syntax': VisualSyntaxData
|
||||
.from_choice(visual_syntax),
|
||||
'contact': ContactData
|
||||
.from_choice(contact),
|
||||
'angle': AngleData
|
||||
.from_choice(angle),
|
||||
'point_of_view': PointOfViewData
|
||||
.from_choice(point_of_view),
|
||||
'distance': DistanceData
|
||||
.from_choice(distance),
|
||||
'modality_lighting': ModalityLightingData
|
||||
.from_choice(modality_lighting),
|
||||
'modality_color': ModalityColorData
|
||||
.from_choice(modality_color),
|
||||
'modality_depth': ModalityDepthData
|
||||
.from_choice(modality_depth),
|
||||
'information_value': InformationValueData
|
||||
.from_choice(information_value),
|
||||
'framing': FramingData
|
||||
.from_choice(framing),
|
||||
'salience': SalienceData
|
||||
.from_choice(salience),
|
||||
}
|
||||
return cls(**kwargs)
|
||||
@@ -0,0 +1,11 @@
|
||||
"""Definition of PointOfViewData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class PointOfViewData(DataModel):
|
||||
"""PointOfViewData data model."""
|
||||
|
||||
frontal: float
|
||||
oblique: float
|
||||
@@ -0,0 +1,14 @@
|
||||
"""Definition of SalienceData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class SalienceData(DataModel):
|
||||
"""SalienceData data model."""
|
||||
|
||||
size: float
|
||||
colour: float
|
||||
tone: float
|
||||
form: float
|
||||
positioning: float
|
||||
@@ -0,0 +1,27 @@
|
||||
"""Definition of VisualSyntaxData data model."""
|
||||
from __future__ import annotations
|
||||
|
||||
from .data_model import DataModel
|
||||
|
||||
|
||||
class VisualSyntaxData(DataModel):
|
||||
"""VisualSyntaxData data model."""
|
||||
|
||||
non_transactional_action: float
|
||||
non_transactional_reaction: float
|
||||
unidirectional_transactional_action: float
|
||||
unidirectional_transactional_reaction: float
|
||||
bidirectional_transactional_action: float
|
||||
bidirectional_transactional_reaction: float
|
||||
conversion: float
|
||||
speech_process: float
|
||||
classification_overt_taxonomy: float
|
||||
analytical_exhaustive: float
|
||||
analytical_disarranged: float
|
||||
analytical_temporal: float
|
||||
analytical_distributed: float
|
||||
analytical_topological: float
|
||||
analytical_exploded: float
|
||||
analytical_inclusive: float
|
||||
symbolic_suggestive: float
|
||||
symbolic_attributive: float
|
||||
+17
-17
@@ -1,21 +1,21 @@
|
||||
version: '3.7'
|
||||
services:
|
||||
app:
|
||||
image: visual_critical_discourse_analysis:dev
|
||||
container_name: visual_critical_discourse_analysis
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- local.env
|
||||
environment:
|
||||
- ENV=DEV
|
||||
ports:
|
||||
- 8050:8050
|
||||
networks:
|
||||
- backend
|
||||
depends_on:
|
||||
- mongo
|
||||
# app:
|
||||
# image: visual_critical_discourse_analysis:dev
|
||||
# container_name: visual_critical_discourse_analysis
|
||||
# build:
|
||||
# context: .
|
||||
# dockerfile: Dockerfile
|
||||
# env_file:
|
||||
# - local.env
|
||||
# environment:
|
||||
# - ENV=DEV
|
||||
# ports:
|
||||
# - 8050:8050
|
||||
# networks:
|
||||
# - backend
|
||||
# depends_on:
|
||||
# - mongo
|
||||
mongo:
|
||||
image: mongo:latest
|
||||
container_name: mongo
|
||||
@@ -41,4 +41,4 @@ services:
|
||||
|
||||
networks:
|
||||
backend:
|
||||
driver: bridge
|
||||
driver: bridge
|
||||
|
||||
@@ -0,0 +1,146 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from io import BytesIO
|
||||
|
||||
from torch import Tensor
|
||||
from torch.utils.data import Dataset
|
||||
from torchvision.io import read_image
|
||||
from torchvision.transforms import ColorJitter
|
||||
from torchvision.transforms import InterpolationMode
|
||||
from torchvision.transforms import Normalize
|
||||
from torchvision.transforms.functional import hflip
|
||||
from torchvision.transforms.functional import pad
|
||||
from torchvision.transforms.functional import resize
|
||||
from torchvision.transforms.functional import rotate
|
||||
|
||||
from core.database import connect
|
||||
|
||||
# resnet18 original normalization values
|
||||
RESNET_NORMALIZE_MEAN = [0.485, 0.456, 0.406]
|
||||
RESNET_NORMALIZE_STD = [0.229, 0.224, 0.225]
|
||||
|
||||
|
||||
class VCDADataset(Dataset):
|
||||
def __init__(
|
||||
self,
|
||||
data_name_list: list[str],
|
||||
do_augment: bool = False,
|
||||
random_annotations: bool = False,
|
||||
normalize_mean: list[float] = RESNET_NORMALIZE_MEAN,
|
||||
normalize_std: list[float] = RESNET_NORMALIZE_STD,
|
||||
):
|
||||
super().__init__()
|
||||
self.data_name_list = data_name_list
|
||||
self.do_augment = do_augment
|
||||
self.random_annotations = random_annotations
|
||||
self.normalize_mean = normalize_mean
|
||||
self.normalize_std = normalize_std
|
||||
# prepare augmentation functions
|
||||
self.normalize = Normalize(
|
||||
mean=normalize_mean,
|
||||
std=normalize_std,
|
||||
)
|
||||
self.color_jitter = ColorJitter(
|
||||
brightness=1e-1,
|
||||
contrast=8e-2,
|
||||
saturation=8e-2,
|
||||
)
|
||||
# connect to database
|
||||
collection, _, _ = connect()
|
||||
self.collection = collection
|
||||
|
||||
def __len__(self):
|
||||
return len(self.data_name_list)
|
||||
|
||||
def __getitem__(self, idx):
|
||||
# get image from database
|
||||
name = self.data_name_list[idx]
|
||||
query = {
|
||||
'name': name,
|
||||
}
|
||||
projection = {
|
||||
'_id': False,
|
||||
'image': True,
|
||||
}
|
||||
img_bytes = self.collection.find_one(
|
||||
filter=query,
|
||||
projection=projection,
|
||||
)
|
||||
img = self.load_image(img_bytes)
|
||||
if self.do_augment:
|
||||
img = self.augment(img)
|
||||
return img
|
||||
|
||||
def load_image(
|
||||
self,
|
||||
data: bytes,
|
||||
) -> Tensor:
|
||||
"""Load images tensor from bytes."""
|
||||
assert isinstance(data, bytes)
|
||||
img = read_image(BytesIO(data))
|
||||
img /= 255 # normalize 8-bit image
|
||||
img = self.square_pad(img)
|
||||
img = resize(
|
||||
img=img,
|
||||
size=(512, 512),
|
||||
interpolation=InterpolationMode.BICUBIC,
|
||||
)
|
||||
return img
|
||||
|
||||
@staticmethod
|
||||
def square_pad(
|
||||
img: Tensor,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Pads image to a square with side length
|
||||
equal to the largest side of the input image.
|
||||
"""
|
||||
assert isinstance(img, Tensor)
|
||||
# B, nc, w, h = img.shape
|
||||
h = img.shape[-2]
|
||||
w = img.shape[-1]
|
||||
if h == w:
|
||||
return img
|
||||
max_wh = max([h, w])
|
||||
hp = int((max_wh - w) / 2)
|
||||
vp = int((max_wh - h) / 2)
|
||||
padding = (hp, vp, hp, vp)
|
||||
return pad(img, padding, 0, 'constant')
|
||||
|
||||
def augment(
|
||||
self,
|
||||
img: Tensor,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Augment image with random horizontal flips,
|
||||
rotations and color jitter.
|
||||
"""
|
||||
assert isinstance(img, Tensor)
|
||||
# left-right flip
|
||||
if random.random() >= 0.5:
|
||||
img = hflip(img)
|
||||
# rotation
|
||||
rnd = random.random()
|
||||
if rnd < 0.25:
|
||||
img = rotate(img, angle=90)
|
||||
if rnd < 0.5:
|
||||
img = rotate(img, angle=180)
|
||||
if rnd < 0.75:
|
||||
img = rotate(img, angle=270)
|
||||
# color jitter
|
||||
img = self.color_jitter(img)
|
||||
return img
|
||||
|
||||
def reverse_normalise(
|
||||
self,
|
||||
img: Tensor,
|
||||
) -> Tensor:
|
||||
"""
|
||||
Reverse normalization to get an image
|
||||
that can be interpreted by humans.
|
||||
"""
|
||||
assert isinstance(img, Tensor)
|
||||
img *= Tensor(self.normalize_std).reshape((3, 1, 1))
|
||||
img += Tensor(self.normalize_mean).reshape((3, 1, 1))
|
||||
return img
|
||||
@@ -0,0 +1,3 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .visual_communication import VisualCommunicationModel
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class AngleTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=3)
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class ContactTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=2)
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class DistanceTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=3)
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class FramingTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=4)
|
||||
@@ -0,0 +1,26 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import torch.nn as nn
|
||||
|
||||
|
||||
class FullyConnectedModel(nn.Module):
|
||||
def __init__(self, num_out_features: int):
|
||||
super().__init__()
|
||||
# define layers
|
||||
self.fc1 = nn.Linear(in_features=16*16*512, out_features=512)
|
||||
self.af1 = nn.ReLU()
|
||||
self.fc2 = nn.Linear(in_features=512, out_features=128)
|
||||
self.af2 = nn.ReLU()
|
||||
self.fc3 = nn.Linear(in_features=128, out_features=32)
|
||||
self.af3 = nn.ReLU()
|
||||
self.fc4 = nn.Linear(in_features=32, out_features=num_out_features)
|
||||
|
||||
def forward(self, x):
|
||||
x = self.fc1(x)
|
||||
x = self.af1(x)
|
||||
x = self.fc2(x)
|
||||
x = self.af2(x)
|
||||
x = self.fc3(x)
|
||||
x = self.af3(x)
|
||||
x = self.fc4(x)
|
||||
return x
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class InformationValueTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=3)
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class ModalityColorTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=3)
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class ModalityDepthTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=3)
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class ModalityLightingTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=3)
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class PointOfViewTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=2)
|
||||
@@ -0,0 +1,37 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import torch.nn as nn
|
||||
import torchvision
|
||||
|
||||
|
||||
class ResNet18Head(nn.Module):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# copy out parts from ResNet18 with weights
|
||||
resnet18 = torchvision.models.resnet18(
|
||||
weights=torchvision.models.ResNet18_Weights.IMAGENET1K_V1,
|
||||
)
|
||||
# save relevant layers
|
||||
self.conv1 = resnet18.conv1
|
||||
self.bn1 = resnet18.bn1
|
||||
self.relu = resnet18.relu
|
||||
self.maxpool = resnet18.maxpool
|
||||
self.layer1 = resnet18.layer1
|
||||
self.layer2 = resnet18.layer2
|
||||
self.layer3 = resnet18.layer3
|
||||
self.layer4 = resnet18.layer4
|
||||
self.avgpool = resnet18.avgpool
|
||||
self.flat = nn.Flatten() # size 512
|
||||
|
||||
def forward(self, x):
|
||||
x = self.conv1(x)
|
||||
x = self.bn1(x)
|
||||
x = self.relu(x)
|
||||
x = self.maxpool(x)
|
||||
x = self.layer1(x)
|
||||
x = self.layer2(x)
|
||||
x = self.layer3(x)
|
||||
x = self.layer4(x)
|
||||
x = self.avgpool(x)
|
||||
x = self.flat(x)
|
||||
return x
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class SalienceTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=5)
|
||||
@@ -0,0 +1,118 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import torch.nn as nn
|
||||
|
||||
from .angle import AngleTail
|
||||
from .contact import ContactTail
|
||||
from .distance import DistanceTail
|
||||
from .framing import FramingTail
|
||||
from .information_value import InformationValueTail
|
||||
from .modality_color import ModalityColorTail
|
||||
from .modality_depth import ModalityDepthTail
|
||||
from .modality_lighting import ModalityLightingTail
|
||||
from .point_of_view import PointOfViewTail
|
||||
from .resnet18_head import ResNet18Head
|
||||
from .salience import SalienceTail
|
||||
from .visual_syntax import VisualSyntaxTail
|
||||
from core.dto import AngleData
|
||||
from core.dto import ContactData
|
||||
from core.dto import DistanceData
|
||||
from core.dto import FramingData
|
||||
from core.dto import InformationValueData
|
||||
from core.dto import ModalityColorData
|
||||
from core.dto import ModalityDepthData
|
||||
from core.dto import ModalityLightingData
|
||||
from core.dto import PointOfViewData
|
||||
from core.dto import SalienceData
|
||||
from core.dto import VisualSyntaxData
|
||||
|
||||
|
||||
class VisualCommunicationModel(nn.Module):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
# store other models
|
||||
self.resnet_head = ResNet18Head()
|
||||
self.visual_syntax_tail = VisualSyntaxTail()
|
||||
self.contact_tail = ContactTail()
|
||||
self.angle_tail = AngleTail()
|
||||
self.point_of_view_tail = PointOfViewTail()
|
||||
self.distance_tail = DistanceTail()
|
||||
self.modality_lighting_tail = ModalityLightingTail()
|
||||
self.modality_color_tail = ModalityColorTail()
|
||||
self.modality_depth_tail = ModalityDepthTail()
|
||||
self.information_value_tail = InformationValueTail()
|
||||
self.framing_tail = FramingTail()
|
||||
self.salience_tail = SalienceTail()
|
||||
|
||||
def forward(self, x):
|
||||
# generate visual representation
|
||||
vis_rep = self.resnet_head(x)
|
||||
# prepare result map
|
||||
results = {}
|
||||
# predict visual syntax
|
||||
results['visual_syntax'] = VisualSyntaxData.from_list(
|
||||
self.visual_syntax_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict contact
|
||||
results['contact'] = ContactData.from_list(
|
||||
self.contact_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict angle
|
||||
results['angle'] = AngleData.from_list(
|
||||
self.angle_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict point of view
|
||||
results['point_of_view'] = PointOfViewData.from_list(
|
||||
self.point_of_view_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict distance
|
||||
results['distance'] = DistanceData.from_list(
|
||||
self.distance_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict modality lighting
|
||||
results['modality_lighting'] = ModalityLightingData.from_list(
|
||||
self.modality_lighting_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict modality color
|
||||
results['modality_color'] = ModalityColorData.from_list(
|
||||
self.modality_color_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict modality depth
|
||||
results['modality_depth'] = ModalityDepthData.from_list(
|
||||
self.modality_depth_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict information value
|
||||
results['information_value'] = InformationValueData.from_list(
|
||||
self.information_value_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict framing
|
||||
results['framing'] = FramingData.from_list(
|
||||
self.framing_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
# predict salience
|
||||
results['salience'] = SalienceData.from_list(
|
||||
self.salience_tail(
|
||||
vis_rep,
|
||||
).cpu(),
|
||||
)
|
||||
return results
|
||||
@@ -0,0 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .fully_connected import FullyConnectedModel
|
||||
|
||||
|
||||
class VisualSyntaxTail(FullyConnectedModel):
|
||||
def __init__(self):
|
||||
super().__init__(num_out_features=18)
|
||||
@@ -0,0 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from dataloader import VCDADataset # noqa: F401
|
||||
from loss_fn import setup_criterion # noqa: F401
|
||||
|
||||
from model import ResNet18Head # noqa: F401
|
||||
Generated
+342
-2
@@ -1,4 +1,4 @@
|
||||
# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand.
|
||||
# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand.
|
||||
|
||||
[[package]]
|
||||
name = "annotated-types"
|
||||
@@ -381,6 +381,22 @@ idna = ["idna (>=3.6)"]
|
||||
trio = ["trio (>=0.23)"]
|
||||
wmi = ["wmi (>=1.5.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "filelock"
|
||||
version = "3.13.1"
|
||||
description = "A platform independent file lock."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"},
|
||||
{file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"]
|
||||
testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"]
|
||||
typing = ["typing-extensions (>=4.8)"]
|
||||
|
||||
[[package]]
|
||||
name = "flake8"
|
||||
version = "7.0.0"
|
||||
@@ -419,6 +435,41 @@ Werkzeug = ">=3.0.0"
|
||||
async = ["asgiref (>=3.2)"]
|
||||
dotenv = ["python-dotenv"]
|
||||
|
||||
[[package]]
|
||||
name = "fsspec"
|
||||
version = "2024.2.0"
|
||||
description = "File-system specification"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "fsspec-2024.2.0-py3-none-any.whl", hash = "sha256:817f969556fa5916bc682e02ca2045f96ff7f586d45110fcb76022063ad2c7d8"},
|
||||
{file = "fsspec-2024.2.0.tar.gz", hash = "sha256:b6ad1a679f760dda52b1168c859d01b7b80648ea6f7f7c7f5a8a91dc3f3ecb84"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
abfs = ["adlfs"]
|
||||
adl = ["adlfs"]
|
||||
arrow = ["pyarrow (>=1)"]
|
||||
dask = ["dask", "distributed"]
|
||||
devel = ["pytest", "pytest-cov"]
|
||||
dropbox = ["dropbox", "dropboxdrivefs", "requests"]
|
||||
full = ["adlfs", "aiohttp (!=4.0.0a0,!=4.0.0a1)", "dask", "distributed", "dropbox", "dropboxdrivefs", "fusepy", "gcsfs", "libarchive-c", "ocifs", "panel", "paramiko", "pyarrow (>=1)", "pygit2", "requests", "s3fs", "smbprotocol", "tqdm"]
|
||||
fuse = ["fusepy"]
|
||||
gcs = ["gcsfs"]
|
||||
git = ["pygit2"]
|
||||
github = ["requests"]
|
||||
gs = ["gcsfs"]
|
||||
gui = ["panel"]
|
||||
hdfs = ["pyarrow (>=1)"]
|
||||
http = ["aiohttp (!=4.0.0a0,!=4.0.0a1)"]
|
||||
libarchive = ["libarchive-c"]
|
||||
oci = ["ocifs"]
|
||||
s3 = ["s3fs"]
|
||||
sftp = ["paramiko"]
|
||||
smb = ["smbprotocol"]
|
||||
ssh = ["paramiko"]
|
||||
tqdm = ["tqdm"]
|
||||
|
||||
[[package]]
|
||||
name = "gunicorn"
|
||||
version = "21.2.0"
|
||||
@@ -588,6 +639,23 @@ files = [
|
||||
{file = "mccabe-0.7.0.tar.gz", hash = "sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mpmath"
|
||||
version = "1.3.0"
|
||||
description = "Python library for arbitrary-precision floating-point arithmetic"
|
||||
optional = false
|
||||
python-versions = "*"
|
||||
files = [
|
||||
{file = "mpmath-1.3.0-py3-none-any.whl", hash = "sha256:a0b2b9fe80bbcd81a6647ff13108738cfb482d481d826cc0e02f5b35e5c88d2c"},
|
||||
{file = "mpmath-1.3.0.tar.gz", hash = "sha256:7a28eb2a9774d00c7bc92411c19a89209d5da7c4c9a9e227be8330a23a25b91f"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
develop = ["codecov", "pycodestyle", "pytest (>=4.6)", "pytest-cov", "wheel"]
|
||||
docs = ["sphinx"]
|
||||
gmpy = ["gmpy2 (>=2.1.0a4)"]
|
||||
tests = ["pytest (>=4.6)"]
|
||||
|
||||
[[package]]
|
||||
name = "mypy"
|
||||
version = "1.8.0"
|
||||
@@ -656,6 +724,24 @@ files = [
|
||||
{file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "networkx"
|
||||
version = "3.2.1"
|
||||
description = "Python package for creating and manipulating graphs and networks"
|
||||
optional = false
|
||||
python-versions = ">=3.9"
|
||||
files = [
|
||||
{file = "networkx-3.2.1-py3-none-any.whl", hash = "sha256:f18c69adc97877c42332c170849c96cefa91881c99a7cb3e95b7c659ebdc1ec2"},
|
||||
{file = "networkx-3.2.1.tar.gz", hash = "sha256:9f1bb5cf3409bf324e0a722c20bdb4c20ee39bf1c30ce8ae499c8502b0b5e0c6"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
default = ["matplotlib (>=3.5)", "numpy (>=1.22)", "pandas (>=1.4)", "scipy (>=1.9,!=1.11.0,!=1.11.1)"]
|
||||
developer = ["changelist (==0.4)", "mypy (>=1.1)", "pre-commit (>=3.2)", "rtoml"]
|
||||
doc = ["nb2plots (>=0.7)", "nbconvert (<7.9)", "numpydoc (>=1.6)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.14)", "sphinx (>=7)", "sphinx-gallery (>=0.14)", "texext (>=0.6.7)"]
|
||||
extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.11)", "sympy (>=1.10)"]
|
||||
test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"]
|
||||
|
||||
[[package]]
|
||||
name = "numpy"
|
||||
version = "1.26.4"
|
||||
@@ -701,6 +787,147 @@ files = [
|
||||
{file = "numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cublas-cu12"
|
||||
version = "12.1.3.1"
|
||||
description = "CUBLAS native runtime libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cublas_cu12-12.1.3.1-py3-none-manylinux1_x86_64.whl", hash = "sha256:ee53ccca76a6fc08fb9701aa95b6ceb242cdaab118c3bb152af4e579af792728"},
|
||||
{file = "nvidia_cublas_cu12-12.1.3.1-py3-none-win_amd64.whl", hash = "sha256:2b964d60e8cf11b5e1073d179d85fa340c120e99b3067558f3cf98dd69d02906"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cuda-cupti-cu12"
|
||||
version = "12.1.105"
|
||||
description = "CUDA profiling tools runtime libs."
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:e54fde3983165c624cb79254ae9818a456eb6e87a7fd4d56a2352c24ee542d7e"},
|
||||
{file = "nvidia_cuda_cupti_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:bea8236d13a0ac7190bd2919c3e8e6ce1e402104276e6f9694479e48bb0eb2a4"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cuda-nvrtc-cu12"
|
||||
version = "12.1.105"
|
||||
description = "NVRTC native runtime libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:339b385f50c309763ca65456ec75e17bbefcbbf2893f462cb8b90584cd27a1c2"},
|
||||
{file = "nvidia_cuda_nvrtc_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:0a98a522d9ff138b96c010a65e145dc1b4850e9ecb75a0172371793752fd46ed"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cuda-runtime-cu12"
|
||||
version = "12.1.105"
|
||||
description = "CUDA Runtime native Libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:6e258468ddf5796e25f1dc591a31029fa317d97a0a94ed93468fc86301d61e40"},
|
||||
{file = "nvidia_cuda_runtime_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:dfb46ef84d73fababab44cf03e3b83f80700d27ca300e537f85f636fac474344"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cudnn-cu12"
|
||||
version = "8.9.2.26"
|
||||
description = "cuDNN runtime libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cudnn_cu12-8.9.2.26-py3-none-manylinux1_x86_64.whl", hash = "sha256:5ccb288774fdfb07a7e7025ffec286971c06d8d7b4fb162525334616d7629ff9"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
nvidia-cublas-cu12 = "*"
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cufft-cu12"
|
||||
version = "11.0.2.54"
|
||||
description = "CUFFT native runtime libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cufft_cu12-11.0.2.54-py3-none-manylinux1_x86_64.whl", hash = "sha256:794e3948a1aa71fd817c3775866943936774d1c14e7628c74f6f7417224cdf56"},
|
||||
{file = "nvidia_cufft_cu12-11.0.2.54-py3-none-win_amd64.whl", hash = "sha256:d9ac353f78ff89951da4af698f80870b1534ed69993f10a4cf1d96f21357e253"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-curand-cu12"
|
||||
version = "10.3.2.106"
|
||||
description = "CURAND native runtime libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_curand_cu12-10.3.2.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:9d264c5036dde4e64f1de8c50ae753237c12e0b1348738169cd0f8a536c0e1e0"},
|
||||
{file = "nvidia_curand_cu12-10.3.2.106-py3-none-win_amd64.whl", hash = "sha256:75b6b0c574c0037839121317e17fd01f8a69fd2ef8e25853d826fec30bdba74a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cusolver-cu12"
|
||||
version = "11.4.5.107"
|
||||
description = "CUDA solver native runtime libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-manylinux1_x86_64.whl", hash = "sha256:8a7ec542f0412294b15072fa7dab71d31334014a69f953004ea7a118206fe0dd"},
|
||||
{file = "nvidia_cusolver_cu12-11.4.5.107-py3-none-win_amd64.whl", hash = "sha256:74e0c3a24c78612192a74fcd90dd117f1cf21dea4822e66d89e8ea80e3cd2da5"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
nvidia-cublas-cu12 = "*"
|
||||
nvidia-cusparse-cu12 = "*"
|
||||
nvidia-nvjitlink-cu12 = "*"
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-cusparse-cu12"
|
||||
version = "12.1.0.106"
|
||||
description = "CUSPARSE native runtime libraries"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-manylinux1_x86_64.whl", hash = "sha256:f3b50f42cf363f86ab21f720998517a659a48131e8d538dc02f8768237bd884c"},
|
||||
{file = "nvidia_cusparse_cu12-12.1.0.106-py3-none-win_amd64.whl", hash = "sha256:b798237e81b9719373e8fae8d4f091b70a0cf09d9d85c95a557e11df2d8e9a5a"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
nvidia-nvjitlink-cu12 = "*"
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-nccl-cu12"
|
||||
version = "2.19.3"
|
||||
description = "NVIDIA Collective Communication Library (NCCL) Runtime"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_nccl_cu12-2.19.3-py3-none-manylinux1_x86_64.whl", hash = "sha256:a9734707a2c96443331c1e48c717024aa6678a0e2a4cb66b2c364d18cee6b48d"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-nvjitlink-cu12"
|
||||
version = "12.4.99"
|
||||
description = "Nvidia JIT LTO Library"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_nvjitlink_cu12-12.4.99-py3-none-manylinux2014_x86_64.whl", hash = "sha256:c6428836d20fe7e327191c175791d38570e10762edc588fb46749217cd444c74"},
|
||||
{file = "nvidia_nvjitlink_cu12-12.4.99-py3-none-win_amd64.whl", hash = "sha256:991905ffa2144cb603d8ca7962d75c35334ae82bf92820b6ba78157277da1ad2"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nvidia-nvtx-cu12"
|
||||
version = "12.1.105"
|
||||
description = "NVIDIA Tools Extension"
|
||||
optional = false
|
||||
python-versions = ">=3"
|
||||
files = [
|
||||
{file = "nvidia_nvtx_cu12-12.1.105-py3-none-manylinux1_x86_64.whl", hash = "sha256:dc21cf308ca5691e7c04d962e213f8a4aa9bbfa23d95412f452254c2caeb09e5"},
|
||||
{file = "nvidia_nvtx_cu12-12.1.105-py3-none-win_amd64.whl", hash = "sha256:65f4d98982b31b60026e0e6de73fbdfc09d08a96f4656dd3665ca616a11e1e82"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "outcome"
|
||||
version = "1.3.0.post0"
|
||||
@@ -1320,6 +1547,20 @@ files = [
|
||||
{file = "sortedcontainers-2.4.0.tar.gz", hash = "sha256:25caa5a06cc30b6b83d11423433f65d1f9d76c4c6a0c90e3379eaa43b9bfdb88"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sympy"
|
||||
version = "1.12"
|
||||
description = "Computer algebra system (CAS) in Python"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "sympy-1.12-py3-none-any.whl", hash = "sha256:c3588cd4295d0c0f603d0f2ae780587e64e2efeedb3521e46b9bb1d08d184fa5"},
|
||||
{file = "sympy-1.12.tar.gz", hash = "sha256:ebf595c8dac3e0fdc4152c51878b498396ec7f30e7a914d6071e674d49420fb8"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
mpmath = ">=0.19"
|
||||
|
||||
[[package]]
|
||||
name = "tenacity"
|
||||
version = "8.2.3"
|
||||
@@ -1334,6 +1575,105 @@ files = [
|
||||
[package.extras]
|
||||
doc = ["reno", "sphinx", "tornado (>=4.5)"]
|
||||
|
||||
[[package]]
|
||||
name = "torch"
|
||||
version = "2.2.1"
|
||||
description = "Tensors and Dynamic neural networks in Python with strong GPU acceleration"
|
||||
optional = false
|
||||
python-versions = ">=3.8.0"
|
||||
files = [
|
||||
{file = "torch-2.2.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:8d3bad336dd2c93c6bcb3268e8e9876185bda50ebde325ef211fb565c7d15273"},
|
||||
{file = "torch-2.2.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:5297f13370fdaca05959134b26a06a7f232ae254bf2e11a50eddec62525c9006"},
|
||||
{file = "torch-2.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:5f5dee8433798888ca1415055f5e3faf28a3bad660e4c29e1014acd3275ab11a"},
|
||||
{file = "torch-2.2.1-cp310-none-macosx_10_9_x86_64.whl", hash = "sha256:b6d78338acabf1fb2e88bf4559d837d30230cf9c3e4337261f4d83200df1fcbe"},
|
||||
{file = "torch-2.2.1-cp310-none-macosx_11_0_arm64.whl", hash = "sha256:6ab3ea2e29d1aac962e905142bbe50943758f55292f1b4fdfb6f4792aae3323e"},
|
||||
{file = "torch-2.2.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:d86664ec85902967d902e78272e97d1aff1d331f7619d398d3ffab1c9b8e9157"},
|
||||
{file = "torch-2.2.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:d6227060f268894f92c61af0a44c0d8212e19cb98d05c20141c73312d923bc0a"},
|
||||
{file = "torch-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:77e990af75fb1675490deb374d36e726f84732cd5677d16f19124934b2409ce9"},
|
||||
{file = "torch-2.2.1-cp311-none-macosx_10_9_x86_64.whl", hash = "sha256:46085e328d9b738c261f470231e987930f4cc9472d9ffb7087c7a1343826ac51"},
|
||||
{file = "torch-2.2.1-cp311-none-macosx_11_0_arm64.whl", hash = "sha256:2d9e7e5ecbb002257cf98fae13003abbd620196c35f85c9e34c2adfb961321ec"},
|
||||
{file = "torch-2.2.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:ada53aebede1c89570e56861b08d12ba4518a1f8b82d467c32665ec4d1f4b3c8"},
|
||||
{file = "torch-2.2.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:be21d4c41ecebed9e99430dac87de1439a8c7882faf23bba7fea3fea7b906ac1"},
|
||||
{file = "torch-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:79848f46196750367dcdf1d2132b722180b9d889571e14d579ae82d2f50596c5"},
|
||||
{file = "torch-2.2.1-cp312-none-macosx_10_9_x86_64.whl", hash = "sha256:7ee804847be6be0032fbd2d1e6742fea2814c92bebccb177f0d3b8e92b2d2b18"},
|
||||
{file = "torch-2.2.1-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:84b2fb322ab091039fdfe74e17442ff046b258eb5e513a28093152c5b07325a7"},
|
||||
{file = "torch-2.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:5c0c83aa7d94569997f1f474595e808072d80b04d34912ce6f1a0e1c24b0c12a"},
|
||||
{file = "torch-2.2.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:91a1b598055ba06b2c386415d2e7f6ac818545e94c5def597a74754940188513"},
|
||||
{file = "torch-2.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:8f93ddf3001ecec16568390b507652644a3a103baa72de3ad3b9c530e3277098"},
|
||||
{file = "torch-2.2.1-cp38-none-macosx_10_9_x86_64.whl", hash = "sha256:0e8bdd4c77ac2584f33ee14c6cd3b12767b4da508ec4eed109520be7212d1069"},
|
||||
{file = "torch-2.2.1-cp38-none-macosx_11_0_arm64.whl", hash = "sha256:6a21bcd7076677c97ca7db7506d683e4e9db137e8420eb4a68fb67c3668232a7"},
|
||||
{file = "torch-2.2.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f1b90ac61f862634039265cd0f746cc9879feee03ff962c803486301b778714b"},
|
||||
{file = "torch-2.2.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:ed9e29eb94cd493b36bca9cb0b1fd7f06a0688215ad1e4b3ab4931726e0ec092"},
|
||||
{file = "torch-2.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:c47bc25744c743f3835831a20efdcfd60aeb7c3f9804a213f61e45803d16c2a5"},
|
||||
{file = "torch-2.2.1-cp39-none-macosx_10_9_x86_64.whl", hash = "sha256:0952549bcb43448c8d860d5e3e947dd18cbab491b14638e21750cb3090d5ad3e"},
|
||||
{file = "torch-2.2.1-cp39-none-macosx_11_0_arm64.whl", hash = "sha256:26bd2272ec46fc62dcf7d24b2fb284d44fcb7be9d529ebf336b9860350d674ed"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
filelock = "*"
|
||||
fsspec = "*"
|
||||
jinja2 = "*"
|
||||
networkx = "*"
|
||||
nvidia-cublas-cu12 = {version = "12.1.3.1", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-cuda-cupti-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-cuda-nvrtc-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-cuda-runtime-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-cudnn-cu12 = {version = "8.9.2.26", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-cufft-cu12 = {version = "11.0.2.54", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-curand-cu12 = {version = "10.3.2.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-cusolver-cu12 = {version = "11.4.5.107", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-cusparse-cu12 = {version = "12.1.0.106", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-nccl-cu12 = {version = "2.19.3", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
nvidia-nvtx-cu12 = {version = "12.1.105", markers = "platform_system == \"Linux\" and platform_machine == \"x86_64\""}
|
||||
sympy = "*"
|
||||
typing-extensions = ">=4.8.0"
|
||||
|
||||
[package.extras]
|
||||
opt-einsum = ["opt-einsum (>=3.3)"]
|
||||
optree = ["optree (>=0.9.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "torchvision"
|
||||
version = "0.17.1"
|
||||
description = "image and video datasets and models for torch deep learning"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "torchvision-0.17.1-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:06418880212b66e45e855dd39f536e7fd48b4e6b034a11dd9fe9e2384afb51ec"},
|
||||
{file = "torchvision-0.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:33d65d0c7fdcb3f7bc1dd8ed30ea3cd7e0587b4ad1b104b5677c8191a8bad9f1"},
|
||||
{file = "torchvision-0.17.1-cp310-cp310-manylinux1_x86_64.whl", hash = "sha256:aaefef2be6a02f206085ce4bb6c0078b03ebf48cb6ff82bd762ff6248475e08e"},
|
||||
{file = "torchvision-0.17.1-cp310-cp310-manylinux2014_aarch64.whl", hash = "sha256:ebe5fdb466aff8a8e8e755de84a843418b6f8d500624752c05eaa638d7700f3d"},
|
||||
{file = "torchvision-0.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:9d4d45a996f4313e9c5db4da71d31508d44f7ccfbf29d3442bdcc2ad13e0b6f3"},
|
||||
{file = "torchvision-0.17.1-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:ea2ccdbf5974e0bf27fd6644a33b19cb0700297cf397bb0469e762c11c6c4105"},
|
||||
{file = "torchvision-0.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9106e32c9f1e70afa8172cf1b064cf9c2998d8dff0769ec69d537b20209ee43d"},
|
||||
{file = "torchvision-0.17.1-cp311-cp311-manylinux1_x86_64.whl", hash = "sha256:5966936c669a08870f6547cd0a90d08b157aeda03293f79e2adbb934687175ed"},
|
||||
{file = "torchvision-0.17.1-cp311-cp311-manylinux2014_aarch64.whl", hash = "sha256:e74f5a26ef8190eab0c38b3f63914fea94e58e3b2f0e5466611c9f63bd91a80b"},
|
||||
{file = "torchvision-0.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:a2109c1a1dcf71e8940d43e91f78c4dd5bf0fcefb3a0a42244102752009f5862"},
|
||||
{file = "torchvision-0.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5d241d2a5fb4e608677fccf6f80b34a124446d324ee40c7814ce54bce888275b"},
|
||||
{file = "torchvision-0.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e0fe98d9d92c23d2262ff82f973242951b9357fb640f8888ac50848bd00f5b45"},
|
||||
{file = "torchvision-0.17.1-cp312-cp312-manylinux1_x86_64.whl", hash = "sha256:32dc5de86d2ade399e11087095674ca08a1649fb322cfe69336d28add467edcb"},
|
||||
{file = "torchvision-0.17.1-cp312-cp312-manylinux2014_aarch64.whl", hash = "sha256:54902877410ffb5458ee52b6d0de4b25cf01496bee736d6825301a5f0398536e"},
|
||||
{file = "torchvision-0.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:cc22c1ed0f1aba3f98fd72b6f60021f57aec1d2f6af518522e8a0a83848de3a8"},
|
||||
{file = "torchvision-0.17.1-cp38-cp38-macosx_10_13_x86_64.whl", hash = "sha256:2621097065fa1c827885e2b52102e839a3541b933b7a90e0fa3c42c3de1bc3cf"},
|
||||
{file = "torchvision-0.17.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:5ce76466af2b5a30573939cae1e6e62e29316ceb3ee748091002f312ab0912f6"},
|
||||
{file = "torchvision-0.17.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:bd5dcd14a32945c72f5c19341add94aa7c23dd7bca2bafde44d0f3c4344d17ed"},
|
||||
{file = "torchvision-0.17.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:dca22795cc02ca0d5ddc08c1422ff620bc9899f63d15dc36f71ef37250e17b75"},
|
||||
{file = "torchvision-0.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:524405457dd97d9ab0e48df502f819d0f41a113ce8f00470bb9926d9d36efcf1"},
|
||||
{file = "torchvision-0.17.1-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:58299a724b37b893c7ce4d0b32ea1480c30e467cc114167964b45f6013f6c2d3"},
|
||||
{file = "torchvision-0.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8a1b17fb158b2b881f2c8796fe1839a624e49d5fd07aa61f6dae60ba4819421a"},
|
||||
{file = "torchvision-0.17.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:429d63eb7551aa4d8f6cdf08d109b5570c20cbcce36d9cb95b24556418e4dc82"},
|
||||
{file = "torchvision-0.17.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:0ecc9a58171bd555aed583bf2f72e7fd6cc4f767c14f8b80b6a8725eacf4ceb1"},
|
||||
{file = "torchvision-0.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:5f427ebee15521edcd836bfe05e86feb5189b5c943b9e3999ed0e3f391fbaa1d"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
numpy = "*"
|
||||
pillow = ">=5.3.0,<8.3.dev0 || >=8.4.dev0"
|
||||
torch = "2.2.1"
|
||||
|
||||
[package.extras]
|
||||
scipy = ["scipy"]
|
||||
|
||||
[[package]]
|
||||
name = "trio"
|
||||
version = "0.24.0"
|
||||
@@ -1486,4 +1826,4 @@ testing = ["big-O", "jaraco.functools", "jaraco.itertools", "more-itertools", "p
|
||||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.12"
|
||||
content-hash = "849178e665e9a43935d7508528a82d8e0e173020b9ee4256e6a25d3e607f1bd8"
|
||||
content-hash = "6c4bb66c774e93a08e4180f3148942edf91e2b5620ea1f6c3e4c30045bb643e5"
|
||||
|
||||
@@ -33,6 +33,11 @@ selenium = "^4.18.1"
|
||||
webdriver-manager = "^4.0.1"
|
||||
retry = "^0.9.2"
|
||||
|
||||
|
||||
[tool.poetry.group.model.dependencies]
|
||||
torch = "^2.2.1"
|
||||
torchvision = "^0.17.1"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .classes import ModelOutputs
|
||||
from .classes import NoDocumentFoundException
|
||||
from .classes import VisualCommunication
|
||||
from .database import connect
|
||||
from .utils import get_visual_communication
|
||||
from .utils import total_annotated
|
||||
from .utils import total_documents
|
||||
from .utils import upsert_annotations
|
||||
from .utils import upsert_predictions
|
||||
from .utils import upsert_visual_communication
|
||||
@@ -1,165 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from base64 import b64decode
|
||||
from base64 import b64encode
|
||||
from io import BytesIO
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
from pydantic import BaseModel
|
||||
from pydantic import field_serializer
|
||||
from pydantic import field_validator
|
||||
|
||||
from src.model_experiential import (
|
||||
VisualSyntaxModelOutput,
|
||||
)
|
||||
from src.model_interpersonal import AngleModelOutput
|
||||
from src.model_interpersonal import ContactModelOutput
|
||||
from src.model_interpersonal import DistanceModelOutput
|
||||
from src.model_interpersonal import ModalityColorModelOutput
|
||||
from src.model_interpersonal import ModalityDepthModelOutput
|
||||
from src.model_interpersonal import ModalityLightingModelOutput
|
||||
from src.model_interpersonal import PointOfViewModelOutput
|
||||
from src.model_textual import FramingModelOutput
|
||||
from src.model_textual import InformationValueModelOutput
|
||||
from src.model_textual import SalienceModelOutput
|
||||
|
||||
|
||||
class NoDocumentFoundException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class ModelOutputs(BaseModel):
|
||||
visual_syntax: VisualSyntaxModelOutput
|
||||
contact: ContactModelOutput
|
||||
angle: AngleModelOutput
|
||||
point_of_view: PointOfViewModelOutput
|
||||
distance: DistanceModelOutput
|
||||
modality_lighting: ModalityLightingModelOutput
|
||||
modality_color: ModalityColorModelOutput
|
||||
modality_depth: ModalityDepthModelOutput
|
||||
information_value: InformationValueModelOutput
|
||||
framing: FramingModelOutput
|
||||
salience: SalienceModelOutput
|
||||
|
||||
@classmethod
|
||||
def list_fields(cls) -> list[str]:
|
||||
"""List options that are stored as attributes."""
|
||||
return list(cls.model_fields.keys())
|
||||
|
||||
@classmethod
|
||||
def from_random(cls) -> ModelOutputs:
|
||||
"""Instantiate with random numbers."""
|
||||
kwargs = {
|
||||
field: field_info.annotation.from_random() # type: ignore
|
||||
for field, field_info
|
||||
in cls.model_fields.items()
|
||||
}
|
||||
return cls(**kwargs)
|
||||
|
||||
@classmethod
|
||||
def from_annotations(
|
||||
cls,
|
||||
visual_syntax: str,
|
||||
contact: str,
|
||||
angle: str,
|
||||
point_of_view: str,
|
||||
distance: str,
|
||||
modality_lighting: str,
|
||||
modality_color: str,
|
||||
modality_depth: str,
|
||||
information_value: str,
|
||||
framing: str,
|
||||
salience: str,
|
||||
) -> ModelOutputs:
|
||||
"""Instantiate from annotation."""
|
||||
kwargs = {
|
||||
'visual_syntax': VisualSyntaxModelOutput
|
||||
.from_choice(visual_syntax),
|
||||
'contact': ContactModelOutput
|
||||
.from_choice(contact),
|
||||
'angle': AngleModelOutput
|
||||
.from_choice(angle),
|
||||
'point_of_view': PointOfViewModelOutput
|
||||
.from_choice(point_of_view),
|
||||
'distance': DistanceModelOutput
|
||||
.from_choice(distance),
|
||||
'modality_lighting': ModalityLightingModelOutput
|
||||
.from_choice(modality_lighting),
|
||||
'modality_color': ModalityColorModelOutput
|
||||
.from_choice(modality_color),
|
||||
'modality_depth': ModalityDepthModelOutput
|
||||
.from_choice(modality_depth),
|
||||
'information_value': InformationValueModelOutput
|
||||
.from_choice(information_value),
|
||||
'framing': FramingModelOutput
|
||||
.from_choice(framing),
|
||||
'salience': SalienceModelOutput
|
||||
.from_choice(salience),
|
||||
}
|
||||
return cls(**kwargs)
|
||||
|
||||
|
||||
class VisualCommunication(BaseModel):
|
||||
name: str
|
||||
image: Image.Image
|
||||
annotation: ModelOutputs | None = None
|
||||
prediction: ModelOutputs | None = None
|
||||
|
||||
class Config:
|
||||
arbitrary_types_allowed = True
|
||||
|
||||
@classmethod
|
||||
def classname(cls) -> str:
|
||||
"""Return classname."""
|
||||
return cls.__name__
|
||||
|
||||
@classmethod
|
||||
def from_file(cls, path: Path) -> VisualCommunication:
|
||||
"""Instantiate from file."""
|
||||
name = path.stem
|
||||
image = Image.open(path)
|
||||
image.load()
|
||||
return VisualCommunication(name=name, image=image)
|
||||
|
||||
@classmethod
|
||||
def decode_image(cls, content: str) -> Image.Image:
|
||||
"""Decode image."""
|
||||
_, content_data = content.split(',')
|
||||
return Image.open(BytesIO(b64decode(content_data)))
|
||||
|
||||
@field_serializer('image')
|
||||
def serialize_image(image: Image.Image) -> bytes: # type: ignore
|
||||
buffer = BytesIO()
|
||||
image.save(buffer, format='JPEG')
|
||||
return buffer.getvalue()
|
||||
|
||||
@field_validator('image', mode='before')
|
||||
@classmethod
|
||||
def convert_to_image(
|
||||
cls,
|
||||
image: Image.Image | BytesIO | bytes,
|
||||
) -> Image.Image:
|
||||
if isinstance(image, bytes):
|
||||
image = BytesIO(image)
|
||||
if isinstance(image, BytesIO):
|
||||
image = Image.open(image)
|
||||
return image
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f"{self.classname()}(name='{self.name}')"
|
||||
|
||||
def webencoded_image(self) -> str:
|
||||
"""Convert image to be displayed on webpage."""
|
||||
# convert images to bytes string
|
||||
buffer = BytesIO()
|
||||
self.image.save(buffer, format='png')
|
||||
img_enc = b64encode(buffer.getvalue()).decode('utf-8')
|
||||
return f"data:image/png;base64, {img_enc}"
|
||||
|
||||
def generate_random_prediction(self, force: bool = False) -> None:
|
||||
"""Generate random prediction values."""
|
||||
if not force and self.prediction is not None:
|
||||
logging.warning('set force=True to overwrite existing values.')
|
||||
self.prediction = ModelOutputs.from_random()
|
||||
@@ -1,24 +0,0 @@
|
||||
from pymongo import MongoClient
|
||||
from dotenv import load_dotenv
|
||||
import logging
|
||||
import os
|
||||
|
||||
|
||||
def connect():
|
||||
"""Connect to MongoDB."""
|
||||
# load env vars
|
||||
load_dotenv()
|
||||
necessary_env_vars = [
|
||||
"MONGO_HOST",
|
||||
"MONGO_DB",
|
||||
"MONGO_COLLECTION"
|
||||
]
|
||||
for env_var in necessary_env_vars:
|
||||
assert env_var in os.environ, f"{env_var} not found"
|
||||
# connect to database
|
||||
client = MongoClient(os.getenv("MONGO_HOST"))
|
||||
db = client[os.getenv("MONGO_DB")]
|
||||
collection = db[os.getenv("MONGO_COLLECTION")]
|
||||
collection.create_index("name", unique=True)
|
||||
logging.info("connected to database")
|
||||
return collection, db, client
|
||||
@@ -1,120 +0,0 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
from pymongo.collection import Collection
|
||||
|
||||
from .classes import ModelOutputs
|
||||
from .classes import NoDocumentFoundException
|
||||
from .classes import VisualCommunication
|
||||
|
||||
|
||||
def total_documents(
|
||||
collection: Collection,
|
||||
) -> int:
|
||||
"""Get total number of documents in database."""
|
||||
return collection.count_documents(filter={})
|
||||
|
||||
|
||||
def total_annotated(
|
||||
collection: Collection,
|
||||
) -> int:
|
||||
"""Get total number of annotated documents in database."""
|
||||
query = {
|
||||
'annotation': {
|
||||
'$ne': None,
|
||||
},
|
||||
}
|
||||
return collection.count_documents(filter=query)
|
||||
|
||||
|
||||
def get_visual_communication(
|
||||
collection: Collection,
|
||||
with_annotation: bool = False,
|
||||
) -> VisualCommunication:
|
||||
"""Get a random visual communication from the database."""
|
||||
query = {}
|
||||
if with_annotation:
|
||||
query['annotation'] = {'$ne': None}
|
||||
else:
|
||||
query['annotation'] = {'$eq': None}
|
||||
data = collection.aggregate([
|
||||
{
|
||||
'$match': query, # find using filters
|
||||
},
|
||||
{
|
||||
'$sample': {
|
||||
'size': 1, # get one random
|
||||
},
|
||||
},
|
||||
])
|
||||
data_list = list(data) # read data from cursor object
|
||||
if len(data_list) == 0:
|
||||
logging.error('failed getting visual communication')
|
||||
raise NoDocumentFoundException()
|
||||
logging.info('finished')
|
||||
return VisualCommunication.model_validate(data_list[0])
|
||||
|
||||
|
||||
def upsert_predictions(
|
||||
collection: Collection,
|
||||
vis_com_name: str,
|
||||
predictions: ModelOutputs,
|
||||
) -> None:
|
||||
"""Upsert prediction data in the database."""
|
||||
query = {
|
||||
'name': vis_com_name,
|
||||
}
|
||||
update = {
|
||||
'$set': {
|
||||
'prediction': predictions.model_dump(),
|
||||
},
|
||||
}
|
||||
res = collection.update_one(
|
||||
filter=query,
|
||||
update=update,
|
||||
upsert=True,
|
||||
)
|
||||
logging.debug('upserted document: %s', res)
|
||||
logging.info('finished')
|
||||
|
||||
|
||||
def upsert_annotations(
|
||||
collection: Collection,
|
||||
vis_com_name: str,
|
||||
annotations: ModelOutputs,
|
||||
) -> None:
|
||||
"""Upserts annotation data in the database."""
|
||||
query = {
|
||||
'name': vis_com_name,
|
||||
}
|
||||
update = {
|
||||
'$set': {
|
||||
'annotation': annotations.model_dump(),
|
||||
},
|
||||
}
|
||||
res = collection.update_one(
|
||||
filter=query,
|
||||
update=update,
|
||||
upsert=True,
|
||||
)
|
||||
logging.info('upserted document: %s', res)
|
||||
logging.info('finished')
|
||||
|
||||
|
||||
def upsert_visual_communication(
|
||||
collection: Collection,
|
||||
visual_communication_list: list[VisualCommunication],
|
||||
) -> bool:
|
||||
"""
|
||||
Upsert VisualCommunication object in the database.
|
||||
Returns bool stating success.
|
||||
"""
|
||||
response = collection.insert_many(
|
||||
[
|
||||
vis_com.model_dump()
|
||||
for vis_com
|
||||
in visual_communication_list
|
||||
],
|
||||
)
|
||||
return response.acknowledged
|
||||
+18
-13
@@ -13,15 +13,14 @@ from dash_auth import BasicAuth
|
||||
from pydantic import ValidationError
|
||||
|
||||
from .layout import app_layout
|
||||
from src.database import connect
|
||||
from src.database import get_visual_communication
|
||||
from src.database import ModelOutputs
|
||||
from src.database import NoDocumentFoundException
|
||||
from src.database import total_annotated
|
||||
from src.database import total_documents
|
||||
from src.database import upsert_annotations
|
||||
from src.database import upsert_visual_communication
|
||||
from src.database import VisualCommunication
|
||||
from core.database import connect
|
||||
from core.database import count_documents
|
||||
from core.database import get_visual_communication
|
||||
from core.database import NoDocumentFoundException
|
||||
from core.database import upsert_annotation
|
||||
from core.database import upsert_visual_communication
|
||||
from core.database import VisualCommunication
|
||||
from core.dto import ModelData
|
||||
|
||||
# setup app
|
||||
app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
|
||||
@@ -82,8 +81,14 @@ def update_progress_bar(
|
||||
logging.info('began updating progress bar')
|
||||
global collection
|
||||
# get values from database
|
||||
num_total = total_documents(collection=collection)
|
||||
num_handled = total_annotated(collection=collection)
|
||||
num_total = count_documents(
|
||||
collection=collection,
|
||||
only_with_annotation=False,
|
||||
)
|
||||
num_handled = count_documents(
|
||||
collection=collection,
|
||||
only_with_annotation=True,
|
||||
)
|
||||
limit = int(num_total/20)
|
||||
label_str = f"{num_handled}/{num_total}" if num_handled >= limit else ''
|
||||
return num_handled, num_total, label_str
|
||||
@@ -200,9 +205,9 @@ def cycle_visual_communication_data(
|
||||
in zip(annotation_keys, annotation_values)
|
||||
}
|
||||
# instantiate ModelOutputs object
|
||||
annotations = ModelOutputs.from_annotations(**annotation_map)
|
||||
annotations = ModelData.from_annotations(**annotation_map)
|
||||
# save data to database
|
||||
upsert_annotations(
|
||||
upsert_annotation(
|
||||
collection=collection,
|
||||
vis_com_name=vis_com_name,
|
||||
annotations=annotations,
|
||||
|
||||
+26
-47
@@ -4,35 +4,24 @@ import dash_mantine_components as dmc
|
||||
from dash import dcc
|
||||
from dash import html
|
||||
|
||||
from src.model_experiential import VisualSyntaxModelOutput
|
||||
from src.model_interpersonal import AngleModelOutput
|
||||
from src.model_interpersonal import ContactModelOutput
|
||||
from src.model_interpersonal import DistanceModelOutput
|
||||
from src.model_interpersonal import ModalityColorModelOutput
|
||||
from src.model_interpersonal import ModalityDepthModelOutput
|
||||
from src.model_interpersonal import ModalityLightingModelOutput
|
||||
from src.model_interpersonal import PointOfViewModelOutput
|
||||
from src.model_textual import FramingModelOutput
|
||||
from src.model_textual import InformationValueModelOutput
|
||||
from src.model_textual import SalienceModelOutput
|
||||
|
||||
|
||||
def generate_option_labels(model) -> list[str]:
|
||||
"""Generate presentable list of attributes from an OutputModel."""
|
||||
labels = [
|
||||
label.replace('_', ' ').title()
|
||||
for label in model.list_fields()
|
||||
]
|
||||
return labels
|
||||
from core.dto import AngleData
|
||||
from core.dto import ContactData
|
||||
from core.dto import DistanceData
|
||||
from core.dto import FramingData
|
||||
from core.dto import InformationValueData
|
||||
from core.dto import ModalityColorData
|
||||
from core.dto import ModalityDepthData
|
||||
from core.dto import ModalityLightingData
|
||||
from core.dto import PointOfViewData
|
||||
from core.dto import SalienceData
|
||||
from core.dto import VisualSyntaxData
|
||||
|
||||
|
||||
def generate_visual_syntax_options_map():
|
||||
"""Generate map of titles and options for visual syntax labels."""
|
||||
options_map = {}
|
||||
# add experiential labels
|
||||
options_map['visual syntax'] = generate_option_labels(
|
||||
VisualSyntaxModelOutput,
|
||||
)
|
||||
options_map['visual syntax'] = VisualSyntaxData.list_fields()
|
||||
return options_map
|
||||
|
||||
|
||||
@@ -40,21 +29,13 @@ def generate_interpersonal_options_map():
|
||||
"""Generate map of titles and options for interpersonal labels."""
|
||||
options_map = {}
|
||||
# add interpersonal labels
|
||||
options_map['contact'] = generate_option_labels(ContactModelOutput)
|
||||
options_map['angle'] = generate_option_labels(AngleModelOutput)
|
||||
options_map['point of view'] = generate_option_labels(
|
||||
PointOfViewModelOutput,
|
||||
)
|
||||
options_map['distance'] = generate_option_labels(DistanceModelOutput)
|
||||
options_map['modality lighting'] = generate_option_labels(
|
||||
ModalityLightingModelOutput,
|
||||
)
|
||||
options_map['modality color'] = generate_option_labels(
|
||||
ModalityColorModelOutput,
|
||||
)
|
||||
options_map['modality depth'] = generate_option_labels(
|
||||
ModalityDepthModelOutput,
|
||||
)
|
||||
options_map['contact'] = ContactData.list_fields()
|
||||
options_map['angle'] = AngleData.list_fields()
|
||||
options_map['point of view'] = PointOfViewData.list_fields()
|
||||
options_map['distance'] = DistanceData.list_fields()
|
||||
options_map['modality lighting'] = ModalityLightingData.list_fields()
|
||||
options_map['modality color'] = ModalityColorData.list_fields()
|
||||
options_map['modality depth'] = ModalityDepthData.list_fields()
|
||||
return options_map
|
||||
|
||||
|
||||
@@ -62,11 +43,9 @@ def generate_textual_options_map():
|
||||
"""Generate map of titles and options for textual labels."""
|
||||
options_map = {}
|
||||
# add textual labels
|
||||
options_map['information value'] = generate_option_labels(
|
||||
InformationValueModelOutput,
|
||||
)
|
||||
options_map['framing'] = generate_option_labels(FramingModelOutput)
|
||||
options_map['salience'] = generate_option_labels(SalienceModelOutput)
|
||||
options_map['information value'] = InformationValueData.list_fields()
|
||||
options_map['framing'] = FramingData.list_fields()
|
||||
options_map['salience'] = SalienceData.list_fields()
|
||||
return options_map
|
||||
|
||||
|
||||
@@ -83,7 +62,7 @@ for title, options in experiential_map.items():
|
||||
dmc.Container([
|
||||
html.B(title.title()),
|
||||
dcc.RadioItems(
|
||||
options=options,
|
||||
options=[text.replace('_', ' ') for text in options],
|
||||
id=id_dict,
|
||||
),
|
||||
]),
|
||||
@@ -101,7 +80,7 @@ for title, options in interpersonal_map.items():
|
||||
dmc.Container([
|
||||
html.B(title.title()),
|
||||
dcc.RadioItems(
|
||||
options=options,
|
||||
options=[text.replace('_', ' ') for text in options],
|
||||
id=id_dict,
|
||||
),
|
||||
]),
|
||||
@@ -117,9 +96,9 @@ for title, options in textual_map.items():
|
||||
id_dict = {'type': 'annotation', 'index': title.replace('_', '-')}
|
||||
textual_container.children.append(
|
||||
dmc.Container([
|
||||
html.B(title),
|
||||
html.B(title.title()),
|
||||
dcc.RadioItems(
|
||||
options=options,
|
||||
options=[text.replace('_', ' ') for text in options],
|
||||
id=id_dict,
|
||||
),
|
||||
]),
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from database import VisualCommunication
|
||||
from core.database.classes import VisualCommunication
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -3,10 +3,11 @@ from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from database import connect
|
||||
from database import get_visual_communication
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import get_visual_communication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
env_path = Path(__file__).parent.parent / 'local.env'
|
||||
|
||||
@@ -3,10 +3,11 @@ from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from database import connect
|
||||
from database import VisualCommunication
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database.classes import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
env_path = Path(__file__).parent.parent / 'local.env'
|
||||
|
||||
@@ -3,11 +3,12 @@ from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from database import connect
|
||||
from database import VisualCommunication
|
||||
from dotenv import load_dotenv
|
||||
from pymongo.errors import DuplicateKeyError
|
||||
|
||||
from core.database import connect
|
||||
from core.database.classes import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# get list of image paths
|
||||
test_dir = Path(__file__).parent
|
||||
|
||||
@@ -5,8 +5,8 @@ from pathlib import Path
|
||||
from dotenv import load_dotenv
|
||||
from pymongo.errors import DuplicateKeyError
|
||||
|
||||
from src.database import connect
|
||||
from src.database import VisualCommunication
|
||||
from core.database import connect
|
||||
from core.database import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# get list of image paths
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from database import ModelOutputs
|
||||
from core.dto import ModelData
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# instantiate data object
|
||||
vis_com_list = [
|
||||
ModelOutputs.from_random()
|
||||
ModelData.from_random()
|
||||
for i
|
||||
in range(3)
|
||||
]
|
||||
|
||||
@@ -4,11 +4,12 @@ import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from database import connect
|
||||
from database import upsert_predictions
|
||||
from database import VisualCommunication
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import upsert_predictions
|
||||
from core.database.classes import VisualCommunication
|
||||
|
||||
if __name__ == '__main__':
|
||||
# setup logging
|
||||
fmt = (
|
||||
|
||||
@@ -3,10 +3,11 @@ from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from database import connect
|
||||
from database import total_annotated
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import total_documents
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
env_path = Path(__file__).parent.parent / 'local.env'
|
||||
@@ -16,5 +17,7 @@ if __name__ == '__main__':
|
||||
# connect to database
|
||||
collection, db, client = connect()
|
||||
# get visual communication
|
||||
num_docs = total_annotated(collection)
|
||||
num_docs = total_documents(
|
||||
collection=collection,
|
||||
)
|
||||
print(f"number of annotated documents in database: {num_docs}")
|
||||
|
||||
@@ -3,10 +3,11 @@ from __future__ import annotations
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from database import connect
|
||||
from database import total_documents
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from core.database import connect
|
||||
from core.database import total_documents
|
||||
|
||||
if __name__ == '__main__':
|
||||
# prepare env vars
|
||||
env_path = Path(__file__).parent.parent / 'local.env'
|
||||
@@ -16,5 +17,7 @@ if __name__ == '__main__':
|
||||
# connect to database
|
||||
collection, db, client = connect()
|
||||
# get visual communication
|
||||
num_docs = total_documents(collection)
|
||||
num_docs = total_documents(
|
||||
collection=collection,
|
||||
)
|
||||
print(f"total number of documents in database: {num_docs}")
|
||||
|
||||
Reference in New Issue
Block a user