Skip to content

Commit

Permalink
Merge branch 'master' into feature/docker-api
Browse files Browse the repository at this point in the history
  • Loading branch information
kshitijrajsharma authored Sep 3, 2024
2 parents 8ead61d + 1aa818c commit 807bbdc
Show file tree
Hide file tree
Showing 6 changed files with 218 additions and 4 deletions.
3 changes: 2 additions & 1 deletion backend/aiproject/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"""

import os

import logging
import dj_database_url
import environ
from corsheaders.defaults import default_headers
Expand Down Expand Up @@ -187,6 +187,7 @@
STATIC_ROOT = os.path.join(BASE_DIR, "api_static")

if DEBUG:
logging.info("Enabling oauthlib insecure transport in debug mode")
os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"


Expand Down
5 changes: 4 additions & 1 deletion backend/api-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@ flower==1.2.0
validators==0.20.0
gpxpy==1.5.0
geojson2osm==0.0.1
osmconflator==0.0.9
osmconflator==0.0.11
orthogonalizer==0.0.4
fairpredictor==0.0.26

rasterio==1.3.8
numpy==1.26.4

# tflite-runtime==2.14.0


15 changes: 15 additions & 0 deletions backend/core/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,9 @@ def train_model(
source_imagery,
feedback=None,
freeze_layers=False,
multimasks=False,
input_contact_spacing=8,
input_boundary_width=3,
):
# importing them here so that it won't be necessary when sending tasks ( api only)
import hot_fair_utilities
Expand Down Expand Up @@ -201,12 +204,22 @@ def train_model(
# preprocess
model_input_image_path = f"{base_path}/input"
preprocess_output = f"/{base_path}/preprocessed"

if multimasks:
logger.info(
"Using multiple masks for training : background, footprint, boundary, contact"
)
else:
logger.info("Using binary masks for training : background, footprint")
preprocess(
input_path=model_input_image_path,
output_path=preprocess_output,
rasterize=True,
rasterize_options=["binary"],
georeference_images=True,
multimasks=multimasks,
input_contact_spacing=input_contact_spacing,
input_boundary_width=input_boundary_width,
)
training_instance.chips_length = get_file_count(
os.path.join(preprocess_output, "chips")
Expand All @@ -229,6 +242,7 @@ def train_model(
),
model_home=os.environ["RAMP_HOME"],
epoch_size=epochs,
multimasks=multimasks,
batch_size=batch_size,
freeze_layers=freeze_layers,
)
Expand All @@ -241,6 +255,7 @@ def train_model(
model="ramp",
model_home=os.environ["RAMP_HOME"],
freeze_layers=freeze_layers,
multimasks=multimasks,
)

# copy final model to output
Expand Down
63 changes: 62 additions & 1 deletion backend/core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ class DatasetViewSet(
class TrainingSerializer(
serializers.ModelSerializer
): # serializers are used to translate models objects to api

multimasks = serializers.BooleanField(required=False, default=False)
input_contact_spacing = serializers.IntegerField(
required=False, default=8, min_value=0, max_value=20
)
input_boundary_width = serializers.IntegerField(
required=False, default=3, min_value=0, max_value=10
)

class Meta:
model = Training
fields = "__all__" # defining all the fields to be included in curd for now , we can restrict few if we want
Expand Down Expand Up @@ -131,6 +140,16 @@ def create(self, validated_data):
user = self.context["request"].user
validated_data["created_by"] = user
# create the model instance
multimasks = validated_data.get("multimasks", False)
input_contact_spacing = validated_data.get("input_contact_spacing", 0.75)
input_boundary_width = validated_data.get("input_boundary_width", 0.5)

pop_keys = ["multimasks", "input_contact_spacing", "input_boundary_width"]

for key in pop_keys:
if key in validated_data.keys():
validated_data.pop(key)

instance = Training.objects.create(**validated_data)

# run your function here
Expand All @@ -143,11 +162,16 @@ def create(self, validated_data):
source_imagery=instance.source_imagery
or instance.model.dataset.source_imagery,
freeze_layers=instance.freeze_layers,
multimasks=multimasks,
input_contact_spacing=input_contact_spacing,
input_boundary_width=input_boundary_width,
)
logging.info("Record saved in queue")

if not instance.source_imagery:
instance.source_imagery = instance.model.dataset.source_imagery
if multimasks:
instance.description += f" Multimask params (ct/bw): {input_contact_spacing}/{input_boundary_width}"
instance.task_id = task.id
instance.save()
print(f"Saved train model request to queue with id {task.id}")
Expand Down Expand Up @@ -583,7 +607,44 @@ def post(self, request, *args, **kwargs):
f"dataset_{model_instance.dataset.id}",
"output",
f"training_{training_instance.id}",
"checkpoint.h5",
"checkpoint.tf",
)
geojson_data = predict(
bbox=bbox,
model_path=model_path,
zoom_level=zoom_level,
tms_url=source,
tile_size=DEFAULT_TILE_SIZE,
confidence=(
deserialized_data["confidence"] / 100
if "confidence" in deserialized_data
else 0.5
),
tile_overlap_distance=(
deserialized_data["tile_overlap_distance"]
if "tile_overlap_distance" in deserialized_data
else 0.15
),
)
print(
f"It took {round(time.time()-start_time)}sec for generating predictions"
)
for feature in geojson_data["features"]:
feature["properties"]["building"] = "yes"
feature["properties"]["source"] = "fAIr"
if use_josm_q is True:
feature["geometry"] = othogonalize_poly(
feature["geometry"],
maxAngleChange=(
deserialized_data["max_angle_change"]
if "max_angle_change" in deserialized_data
else 15
),
skewTolerance=(
deserialized_data["skew_tolerance"]
if "skew_tolerance" in deserialized_data
else 15
),
)
if not os.path.exists(model_path):
model_path = os.path.join(
Expand Down
1 change: 1 addition & 0 deletions backend/fAIr-utilities
Submodule fAIr-utilities added at 93debb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import axios from "../../../../axios";
import { useMutation, useQuery } from "react-query";
import Popup from "./Popup";

import { Accordion, AccordionSummary, AccordionDetails } from "@mui/material";
import ExpandMoreIcon from "@mui/icons-material/ExpandMore";

import OSMUser from "../../../Shared/OSMUser";
import SaveIcon from "@material-ui/icons/Save";
import { Checkbox, FormControlLabel } from "@mui/material";
Expand All @@ -35,6 +38,10 @@ const AIModelEditor = (props) => {
const [sourceImagery, setSourceImagery] = React.useState(null);
const [freezeLayers, setFreezeLayers] = useState(false);

const [multimasks, setMultimasks] = React.useState(false);
const [inputContactSpacing, setInputContactSpacing] = React.useState(4);
const [inputBoundaryWidth, setInputBoundaryWidth] = React.useState(2);

const [popupRowData, setPopupRowData] = useState(null);
const [feedbackCount, setFeedbackCount] = useState(0);
const [feedbackData, setFeedbackData] = useState(null);
Expand Down Expand Up @@ -123,6 +130,9 @@ const AIModelEditor = (props) => {
model: id,
zoom_level: zoomLevel,
description: description,
input_contact_spacing: inputContactSpacing,
input_boundary_width: inputBoundaryWidth,
multimasks: multimasks,
};
const headers = {
"access-token": accessToken,
Expand Down Expand Up @@ -310,7 +320,7 @@ const AIModelEditor = (props) => {
helperText={
<span>
A short description to document why you submitted this
training
training or extra additional info
</span>
}
type="text"
Expand Down Expand Up @@ -339,6 +349,129 @@ const AIModelEditor = (props) => {
</FormGroup>
</FormControl>
</Grid> */}
<Grid item xs={6}>
<Accordion sx={{ boxShadow: "none", background: "none" }}>
<AccordionSummary
expandIcon={<ExpandMoreIcon sx={{ fontSize: "1rem" }} />}
aria-controls="panel1a-content"
id="panel1a-header"
sx={{
minHeight: "32px",
height: "32px",
background: "white !important",
"& .MuiAccordionSummary-content": {
margin: "0",
alignItems: "center",
},
"& .MuiAccordionSummary-expandIconWrapper": {
padding: "0",
"&.Mui-expanded": {
transform: "rotate(180deg)",
},
},
// Prevent changes in background or elevation when expanded
"&.Mui-expanded": {
minHeight: "32px",
margin: "0",
},
"&:hover": {
background: "white",
},
"&.Mui-focusVisible": {
backgroundColor: "white",
},
}}
>
<Typography
variant="body2"
sx={{ color: "primary", fontSize: "0.875rem" }}
>
Advanced Parameters
</Typography>
</AccordionSummary>
<AccordionDetails sx={{ padding: "8px 16px 16px" }}>
<Grid container spacing={1}>
<Grid item xs={12}>
<FormControlLabel
control={
<Checkbox
sx={{ transform: "scale(0.8)", marginLeft: "-10px" }}
checked={multimasks}
onChange={(e) => setMultimasks(e.target.checked)}
name="multimasks"
/>
}
label={
<Typography
variant="body2"
sx={{ fontSize: "0.875rem", padding: "1" }}
>
Take boundary of footprints into account during
training
</Typography>
}
sx={{ margin: "0" }}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
size="small"
id="input-contact-spacing"
label="Input Contact Spacing"
type="number"
helperText={
<span>
Enter the distance in pixels to extend the area around
each building. This will be used to find points where
buildings come into contact or are in close proximity
to one another. For example, entering '8' will explore
areas within 8 pixels outside the original building
shapes to detect nearby buildings
</span>
}
value={inputContactSpacing}
fullWidth
onChange={(e) => setInputContactSpacing(e.target.value)}
InputProps={{
sx: { fontSize: "0.875rem", height: "40px" },
}}
InputLabelProps={{
sx: { fontSize: "0.875rem" },
}}
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
size="small"
id="input-boundary-width"
label="Input Boundary Width"
type="number"
value={inputBoundaryWidth}
helperText={
<span>
Specify the width in pixels to reduce the original
building shape inwardly, creating a boundary or margin
around each building. A smaller value creates a
tighter boundary close to the building's edges, while
a larger value creates a wider surrounding area. For
example, entering '3' will create a boundary that 3
pixles inside from the original building edges.
</span>
}
fullWidth
onChange={(e) => setInputBoundaryWidth(e.target.value)}
InputProps={{
sx: { fontSize: "0.875rem", height: "40px" },
}}
InputLabelProps={{
sx: { fontSize: "0.875rem" },
}}
/>
</Grid>
</Grid>
</AccordionDetails>
</Accordion>
</Grid>

<Grid item xs={12} md={12}></Grid>
<Grid item xs={6} md={6}>
Expand Down

0 comments on commit 807bbdc

Please sign in to comment.