Skip to content

Commit 61256ea

Browse files
committed
Merge remote-tracking branch 'origin/next' into nme_gpu
2 parents 6c40da2 + 151d98d commit 61256ea

File tree

16 files changed

+1103
-86
lines changed

16 files changed

+1103
-86
lines changed

celery_app/register.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,10 @@ def register(is_heartbeat: bool = False) -> bool:
6060
def unregister() -> None:
6161
"""Un-register the service"""
6262
try:
63+
password = os.environ.get("BROKER_PASS", None)
6364
host, port = os.environ.get("SERVICES_BROKER").split("//")[1].split(":")
6465
r = redis.Redis(
65-
host=host, port=int(port), db=SERVICE_DISCOVERY_DB, password="password"
66+
host=host, port=int(port), db=SERVICE_DISCOVERY_DB, password=password
6667
)
6768
r.json().delete(f"service:{host_name}")
6869
except Exception as error:

docker-entrypoint.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ run_celery_worker() {
5050
python -c "from celery_app.register import register; register()" || exit $?
5151
echo "Service registered"
5252
## WORKER
53-
celery --app=celery_app.celeryapp worker $OPT -Ofair -n diarization_worker@%h --queues=$QUEUE -c ${CONCURRENCY:-1} || exit $?
53+
celery --app=celery_app.celeryapp worker $OPT -Ofair -n ${SERVICE_NAME}_worker@%h --queues=$QUEUE -c ${CONCURRENCY:-1} || exit $?
5454
## UNREGISTERING
5555
python -c "from celery_app.register import unregister; unregister()" || exit $?
5656
echo "Service unregistered"

healthcheck.sh

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,27 @@ if [ "$SERVICE_MODE" = "http" ]
66
then
77
curl --fail http://localhost:80/healthcheck || exit 1
88
else
9-
# Update last alive, using Heartbeat(register(True))
10-
python -c "from celery_app.register import register; register(True)"
9+
# Update last alive
10+
python -c "from celery_app.register import register; register(False)"
1111

1212
# Check if Celery worker process is running
1313
# warning : We might rework this when switching to non-root user. Which is required for security reasons.
1414
# Our docker images are currently running as root and this is bad :)
15-
if ! pgrep -f "celeryapp worker"; then
15+
PID=`pgrep -f "celeryapp worker"`
16+
if [ -z "$PID" ]; then
1617
echo "HealtchCheck FAIL : Celery worker process not running"
1718
exit 1
1819
fi
1920

20-
# Check GPU utilization
21-
if nvidia-smi --query-gpu=utilization.gpu --format=csv,noheader,nounits | grep -v '^0$'; then
22-
#"GPU is being utilized, assuming healthy"
23-
exit 0
24-
else
25-
# If GPU is not being utilized, attempt a ping as a secondary check
26-
if ! celery --app=celery_app.celeryapp inspect ping -d ${SERVICE_NAME}_worker@$HOSTNAME --timeout=20; then
27-
echo "HealtchCheck FAIL : Celery worker not responding in time and GPU is not being utilized"
28-
exit 1
21+
# Attempt a ping
22+
if ! celery --app=celery_app.celeryapp inspect ping -d ${SERVICE_NAME}_worker@$HOSTNAME --timeout=20; then
23+
# Check GPU utilization
24+
if nvidia-smi --query-compute-apps pid --format=csv,noheader | grep $PID; then
25+
# GPU is being utilized, assuming healthy
26+
echo "Celery worker not responding in time but GPU is being utilized (trying to ping again)"
27+
exit 0
2928
fi
29+
echo "HealtchCheck FAIL : Celery worker not responding in time and GPU is not being utilized"
30+
exit 1
3031
fi
3132
fi

simple/.envdefault

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CONCURRENCY=2
1111

1212
# Enforce used device ("cpu" or "cuda")
1313
# DEVICE=cpu
14+
# DEVICE_CLUSTERING=cpu
1415

1516
# Maximum number of threads on CPU
1617
NUM_THREADS=4

simple/Dockerfile

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,4 @@
1-
# base stage target - common dependencies
2-
FROM python:3.10-slim as base
3-
4-
# Set a common work directory
5-
WORKDIR /usr/src/app
6-
7-
# Installing dependencies
8-
9-
# Copy application code
10-
COPY celery_app /usr/src/app/celery_app
11-
COPY http_server /usr/src/app/http_server
12-
COPY document /usr/src/app/document
13-
COPY docker-entrypoint.sh wait-for-it.sh healthcheck.sh ./
14-
COPY simple/diarization /usr/src/app/diarization
15-
COPY simple/requirements.txt /usr/src/app/
16-
COPY simple/RELEASE.md ./
17-
18-
############################################################################################################
19-
20-
# Here we might build a specific image for the CPU target, use different dependencies, entrypoints, etc.
21-
# using : FROM base as cpu
22-
# not relevant for this dockerfile
23-
24-
############################################################################################################
25-
26-
# gpu stage target - python app with nvidia/cuda base image
27-
FROM nvidia/cuda:12.3.2-base-ubuntu22.04 as gpu
1+
FROM python:3.10
282
293

304
# Re-Sets work directory (not sure if this is necessary)
@@ -37,13 +11,23 @@ RUN apt-get update && \
3711
rm -rf /var/lib/apt/lists/* && \
3812
ln -s /usr/bin/python3.10 /usr/bin/python
3913

14+
# # Set a common work directory
15+
WORKDIR /usr/src/app
16+
4017
# Install python packages
4118
# Reuse labels and base dependencies from the base stage
42-
COPY --from=base /usr/src/app/requirements.txt /usr/src/app/requirements.txt
43-
RUN pip install --no-cache-dir -r requirements.txt
19+
COPY simple/requirements.txt /usr/src/app/requirements.txt
20+
RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt
4421

45-
# Reuse labels and base dependencies from the base stage
46-
COPY --from=base /usr/src/app /usr/src/app
22+
23+
# Copy application code
24+
COPY celery_app /usr/src/app/celery_app
25+
COPY http_server /usr/src/app/http_server
26+
COPY document /usr/src/app/document
27+
COPY docker-entrypoint.sh wait-for-it.sh healthcheck.sh ./
28+
COPY simple/diarization /usr/src/app/diarization
29+
COPY simple/requirements.txt /usr/src/app/
30+
COPY simple/RELEASE.md ./
4731

4832
# Set path
4933
ENV PYTHONPATH="${PYTHONPATH}:/usr/src/app/diarization"

simple/Dockerfile.stagewise

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# base stage target - common dependencies
2+
FROM python:3.10-slim as base
3+
4+
# Set a common work directory
5+
WORKDIR /usr/src/app
6+
7+
# Installing dependencies
8+
9+
# Copy application code
10+
COPY celery_app /usr/src/app/celery_app
11+
COPY http_server /usr/src/app/http_server
12+
COPY document /usr/src/app/document
13+
COPY docker-entrypoint.sh wait-for-it.sh healthcheck.sh ./
14+
COPY simple/diarization /usr/src/app/diarization
15+
COPY simple/requirements.txt /usr/src/app/
16+
COPY simple/RELEASE.md ./
17+
18+
############################################################################################################
19+
20+
# Here we might build a specific image for the CPU target, use different dependencies, entrypoints, etc.
21+
# using : FROM base as cpu
22+
# not relevant for this dockerfile
23+
24+
############################################################################################################
25+
26+
# gpu stage target - python app with nvidia/cuda base image
27+
FROM nvidia/cuda:12.3.2-base-ubuntu22.04 as gpu
28+
29+
30+
# Re-Sets work directory (not sure if this is necessary)
31+
WORKDIR /usr/src/app
32+
33+
# Install python and other dependencies
34+
RUN apt-get update && \
35+
apt-get install -y python3.10 python3-pip ffmpeg git && \
36+
apt-get clean && \
37+
rm -rf /var/lib/apt/lists/* && \
38+
ln -s /usr/bin/python3.10 /usr/bin/python
39+
40+
# Install python packages
41+
# Reuse labels and base dependencies from the base stage
42+
COPY --from=base /usr/src/app/requirements.txt /usr/src/app/requirements.txt
43+
RUN pip install --no-cache-dir -r requirements.txt
44+
45+
# Reuse labels and base dependencies from the base stage
46+
COPY --from=base /usr/src/app /usr/src/app
47+
48+
# Set path
49+
ENV PYTHONPATH="${PYTHONPATH}:/usr/src/app/diarization"
50+
51+
# Extract version information
52+
RUN export VERSION=$(awk -v RS='' '/#/ {print; exit}' RELEASE.md | head -1 | sed 's/#//' | sed 's/ //')
53+
54+
# Health check and entrypoint for GPU target
55+
HEALTHCHECK CMD ./healthcheck.sh
56+
ENTRYPOINT ["./docker-entrypoint.sh"]

simple/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ An example of .env file is provided in [simple/.envdefault](https://github.com/l
5959
|:-|:-|:-|
6060
| `SERVING_MODE` | (Required) Specify launch mode | `http` |
6161
| `CONCURRENCY` | Number of worker(s) additional to the main worker | `0` \| `1` \| `2` \| ... |
62+
| `DEVICE` | Device to use for the embedding model (by default, GPU/CUDA is used if it is available, CPU otherwise) | `cpu` \| `cuda` |
63+
| `DEVICE_CLUSTERING` | Device to use for clustering (by default, GPU/CUDA is used if it is available, CPU otherwise) | `cpu` \| `cuda` |
6264
| `NUM_THREADS` | Number of threads (maximum) to use for things running on CPU | `1` \| `4` \| ... |
6365
| `DEVICE` | Device to use for the embeddings model (by default, GPU/CUDA is used if it is available, CPU otherwise) | `cpu` \| `cuda` \| `cuda:1` ... |
6466
| `DEVICE_VAD` | Device to use for the Voice Activity Detection (by default, CPU) | `cpu` \| `cuda` \| `cuda:1` ... |

simple/RELEASE.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
# 1.0.2
1+
# 1.1.0
2+
- Use NEMO spectral clustering, with DEVICE_CLUSTERING environment variable to enforce using CPU ("cpu") or GPU ("cuda")
3+
- Switch from silero VAD version 4 to version 3.1 (less problems)
24
- Fix healthcheck on GPU
35

46
# 1.0.1

simple/diarization/processing/__init__.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33

44

55
device = os.environ.get("DEVICE")
6-
if device is None:
7-
USE_GPU = torch.cuda.is_available()
6+
device_vad = "cpu" # Not implemented os.environ.get("DEVICE_VAD", "cpu")
7+
device_clustering = os.environ.get("DEVICE_CLUSTERING")
8+
if torch.cuda.is_available():
9+
USE_GPU = (
10+
device != "cpu"
11+
or device_clustering != "cpu"
12+
or device_vad != "cpu"
13+
)
814
else:
9-
USE_GPU = (device != "cpu")
15+
USE_GPU = False
1016

1117
device_vad = os.environ.get("DEVICE_VAD", "cpu")
1218
device_clustering = os.environ.get("DEVICE_CLUSTERING", "cpu")
@@ -21,6 +27,6 @@
2127

2228
from .speakerdiarization import SpeakerDiarization
2329

24-
diarizationworker = SpeakerDiarization(device=device, device_vad=device_vad, device_clustering=device_clustering, num_threads=NUM_THREADS)
30+
diarizationworker = SpeakerDiarization(device=device, device_clustering=device_clustering, device_vad=device_vad, num_threads=NUM_THREADS)
2531

2632
__all__ = ["diarizationworker"]

simple/diarization/processing/simple_diarizer/simple_diarizer/cluster.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,14 @@
66
from sklearn.cluster import AgglomerativeClustering, KMeans, SpectralClustering
77
from sklearn.metrics import pairwise_distances
88
from .spectral_clustering import NME_SpectralClustering
9-
from sklearn.metrics.pairwise import cosine_similarity
9+
10+
from .nmesc_clustering import (
11+
NMESC,
12+
getCosAffinityMatrix,
13+
getAffinityGraphMat,
14+
_SpectralClustering,
15+
)
16+
1017

1118
def cluster_AHC(embeds, n_clusters=None, threshold=None, metric="cosine", **kwargs):
1219
"""
@@ -80,21 +87,42 @@ def cluster_SC(embeds, n_clusters=None, max_speakers= None, threshold=None, enha
8087
def cluster_NME_SC(embeds, n_clusters=None, max_speakers= None, threshold=None, enhance_sim=True, device=None, **kwargs):
8188
"""
8289
Cluster embeds using NME-Spectral Clustering
90+
"""
8391

84-
if n_clusters is None:
85-
assert threshold, "If num_clusters is not defined, threshold must be defined"
8692
"""
8793
88-
#S = cos_similarity(embeds)
89-
S = getCosAffinityMatrix(embeds)
94+
S = getCosAffinityMatrix(embeds) #cos_similarity(embeds)
9095
9196
labels = NME_SpectralClustering(
9297
S,
9398
num_clusters=n_clusters,
9499
max_num_clusters=max_speakers,
95100
device=device,
96101
)
97-
102+
103+
"""
104+
105+
mat = getCosAffinityMatrix(embeds)
106+
nmesc = NMESC(
107+
mat,
108+
max_num_speaker=max_speakers,
109+
max_rp_threshold=0.25,
110+
sparse_search=True,
111+
sparse_search_volume=30,
112+
fixed_thres=None,
113+
NME_mat_size=512,
114+
device=device
115+
116+
)
117+
118+
119+
est_num_of_spk, p_hat_value = nmesc.NMEanalysis()
120+
affinity_mat = getAffinityGraphMat(mat, p_hat_value)
121+
if n_clusters is not None:
122+
est_num_of_spk = n_clusters
123+
spectral_model = _SpectralClustering(n_clusters=est_num_of_spk, device=device)
124+
labels = spectral_model.predict(affinity_mat)
125+
98126
return labels
99127

100128
from sklearn.preprocessing import MinMaxScaler

0 commit comments

Comments
 (0)