quinkgl 0.1.2__tar.gz → 0.1.16__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {quinkgl-0.1.2/src/quinkgl.egg-info → quinkgl-0.1.16}/PKG-INFO +1 -1
- {quinkgl-0.1.2 → quinkgl-0.1.16}/pyproject.toml +1 -1
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/gossip_community.py +59 -19
- {quinkgl-0.1.2 → quinkgl-0.1.16/src/quinkgl.egg-info}/PKG-INFO +1 -1
- {quinkgl-0.1.2 → quinkgl-0.1.16}/MANIFEST.in +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/README.md +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/requirements.txt +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/setup.cfg +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/aggregation/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/aggregation/base.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/aggregation/fedavg.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/config.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/core/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/core/context.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/core/dummy_model.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/core/model_interface.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/core/node.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/data/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/data/datasets.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/gossip/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/gossip/orchestrator.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/gossip/protocol.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/models/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/models/base.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/models/pytorch.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/models/tensorflow.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/connection_manager.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/gossip_node.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/gossip_pb2.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/gossip_pb2_grpc.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/grpc_node.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/ipv8_community.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/ipv8_manager.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/model_serializer.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/tunnel_client.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/tunnel_pb2.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/network/tunnel_pb2_grpc.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/storage/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/storage/model_store.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/topology/__init__.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/topology/base.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/topology/cyclon.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/topology/random.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/topology/sampler.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl/utils/serialization.py +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl.egg-info/SOURCES.txt +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl.egg-info/dependency_links.txt +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl.egg-info/requires.txt +0 -0
- {quinkgl-0.1.2 → quinkgl-0.1.16}/src/quinkgl.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quinkgl
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: A decentralized gossip learning framework for P2P edge intelligence
|
|
5
5
|
Author-email: Ali Seyhan <aliseyhan@posta.mu.edu.tr>, Baki Turhan <bakiturhan@posta.mu.edu.tr>
|
|
6
6
|
Project-URL: Homepage, https://github.com/aliseyhann/QuinkGL-Gossip-Learning-Framework
|
|
@@ -8,6 +8,7 @@ CHUNKED TRANSFER: Large model updates are split into chunks
|
|
|
8
8
|
to work around UDP MTU limits (~1400 bytes).
|
|
9
9
|
"""
|
|
10
10
|
|
|
11
|
+
import asyncio
|
|
11
12
|
import time
|
|
12
13
|
import logging
|
|
13
14
|
import hashlib
|
|
@@ -30,7 +31,7 @@ MAX_INCOMING_MESSAGE_SIZE = 150 * 1024 * 1024
|
|
|
30
31
|
# Chunk size for large model transfers
|
|
31
32
|
# Using 60KB which is below UDP's 65507 byte limit but reduces packet count significantly
|
|
32
33
|
# A 5.8MB model = ~100 chunks instead of ~5800 chunks
|
|
33
|
-
CHUNK_SIZE =
|
|
34
|
+
CHUNK_SIZE = 10000 # 10KB chunks - smaller for better NAT traversal
|
|
34
35
|
|
|
35
36
|
# Timeout for incomplete transfers (300 seconds - increased for Colab/slow networks)
|
|
36
37
|
CHUNK_TRANSFER_TIMEOUT = 300
|
|
@@ -521,6 +522,7 @@ class GossipLearningCommunity(Community):
|
|
|
521
522
|
model_version=payload.model_version
|
|
522
523
|
)
|
|
523
524
|
self.known_peers[payload.node_id] = peer_info
|
|
525
|
+
print(f" 🔗 Peer adresi: {payload.node_id} @ {peer.address}")
|
|
524
526
|
logger.info(f"✅ Discovered compatible peer: {payload.node_id}")
|
|
525
527
|
|
|
526
528
|
if self.on_peer_discovered_callback:
|
|
@@ -590,22 +592,27 @@ class GossipLearningCommunity(Community):
|
|
|
590
592
|
|
|
591
593
|
Buffers chunks and triggers model processing when all chunks are received.
|
|
592
594
|
"""
|
|
593
|
-
|
|
595
|
+
print(f" [DEBUG] on_model_chunk called: chunk {payload.chunk_index}/{payload.total_chunks}")
|
|
596
|
+
transfer_id = f"{payload.sender_id}:{payload.round_number}" # Use sender:round as key
|
|
594
597
|
|
|
595
|
-
# Log chunk receipt
|
|
598
|
+
# Log chunk receipt with visible print statements
|
|
596
599
|
if payload.chunk_index == 0:
|
|
600
|
+
print(f" 📥 Chunk alımı başladı: {payload.sender_id} ({payload.total_chunks} chunk)")
|
|
597
601
|
logger.info(
|
|
598
602
|
f"[NET] Receiving chunked model from {payload.sender_id} "
|
|
599
603
|
f"(transfer={transfer_id[:8]}..., chunks={payload.total_chunks}, "
|
|
600
604
|
f"round={payload.round_number})"
|
|
601
605
|
)
|
|
602
|
-
elif payload.chunk_index == payload.total_chunks - 1:
|
|
606
|
+
elif (payload.chunk_index + 1) % 50 == 0 or payload.chunk_index == payload.total_chunks - 1:
|
|
607
|
+
progress = (payload.chunk_index + 1) / payload.total_chunks * 100
|
|
608
|
+
print(f" 📥 Alındı: {payload.chunk_index + 1}/{payload.total_chunks} ({progress:.0f}%)")
|
|
609
|
+
|
|
610
|
+
if payload.chunk_index == payload.total_chunks - 1:
|
|
603
611
|
logger.info(f"[NET] Received final chunk {payload.chunk_index + 1}/{payload.total_chunks} from {payload.sender_id}")
|
|
604
|
-
elif payload.chunk_index % 100 == 0:
|
|
605
|
-
logger.debug(f"[NET] Chunk progress: {payload.chunk_index + 1}/{payload.total_chunks} from {payload.sender_id}")
|
|
606
612
|
|
|
607
613
|
# Create or get buffer for this transfer
|
|
608
614
|
if transfer_id not in self._chunk_buffers:
|
|
615
|
+
print(f" 🆕 Yeni buffer oluşturuldu: {transfer_id[:8]}... (chunk {payload.chunk_index})")
|
|
609
616
|
self._chunk_buffers[transfer_id] = ChunkBuffer(
|
|
610
617
|
transfer_id=transfer_id,
|
|
611
618
|
sender_id=payload.sender_id,
|
|
@@ -625,6 +632,14 @@ class GossipLearningCommunity(Community):
|
|
|
625
632
|
# Update peer last seen
|
|
626
633
|
if payload.sender_id in self.known_peers:
|
|
627
634
|
self.known_peers[payload.sender_id].update_seen()
|
|
635
|
+
|
|
636
|
+
# NAT keepalive: Send heartbeat every 5 chunks to keep NAT hole open
|
|
637
|
+
if payload.chunk_index % 5 == 0:
|
|
638
|
+
peer_info = self.known_peers[payload.sender_id]
|
|
639
|
+
self.ez_send(peer_info.peer, HeartbeatPayload(
|
|
640
|
+
self.node_id,
|
|
641
|
+
self._heartbeat_sequence
|
|
642
|
+
))
|
|
628
643
|
|
|
629
644
|
# If all chunks received, reassemble and process
|
|
630
645
|
if is_complete:
|
|
@@ -658,21 +673,38 @@ class GossipLearningCommunity(Community):
|
|
|
658
673
|
|
|
659
674
|
# Call callback
|
|
660
675
|
if self.on_model_update_callback:
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
676
|
+
print(f" ✅ Model reassemble tamamlandı, callback çağrılıyor...")
|
|
677
|
+
try:
|
|
678
|
+
await self.on_model_update_callback(
|
|
679
|
+
sender_id=payload.sender_id,
|
|
680
|
+
weights=weights,
|
|
681
|
+
sample_count=buffer.sample_count,
|
|
682
|
+
round_number=buffer.round_number,
|
|
683
|
+
loss=buffer.loss,
|
|
684
|
+
accuracy=buffer.accuracy
|
|
685
|
+
)
|
|
686
|
+
print(f" ✅ Callback başarılı!")
|
|
687
|
+
except Exception as cb_err:
|
|
688
|
+
print(f" ❌ Callback hatası: {cb_err}")
|
|
689
|
+
import traceback
|
|
690
|
+
traceback.print_exc()
|
|
691
|
+
else:
|
|
692
|
+
print(f" ⚠️ Callback yok!")
|
|
669
693
|
|
|
670
694
|
except Exception as e:
|
|
671
695
|
logger.error(f"Failed to reassemble/process chunked model from {payload.sender_id}: {e}")
|
|
672
696
|
if transfer_id in self._chunk_buffers:
|
|
673
697
|
del self._chunk_buffers[transfer_id]
|
|
674
|
-
|
|
675
|
-
|
|
698
|
+
else:
|
|
699
|
+
# Debug: if this is the final chunk but buffer is not complete, log missing chunks
|
|
700
|
+
if payload.chunk_index == payload.total_chunks - 1:
|
|
701
|
+
actual_chunks = len(buffer.chunks)
|
|
702
|
+
print(f" ⚠️ DEBUG: Son chunk alındı ama buffer complete değil!")
|
|
703
|
+
print(f" Buffer: {actual_chunks}/{buffer.total_chunks} chunks")
|
|
704
|
+
missing = [i for i in range(buffer.total_chunks) if i not in buffer.chunks][:10]
|
|
705
|
+
print(f" Eksik chunk indexleri: {missing}...")
|
|
706
|
+
|
|
707
|
+
async def send_model_update(
|
|
676
708
|
self,
|
|
677
709
|
target_node_id: str,
|
|
678
710
|
weights: Any,
|
|
@@ -731,6 +763,9 @@ class GossipLearningCommunity(Community):
|
|
|
731
763
|
transfer_id = str(uuid.uuid4())
|
|
732
764
|
total_chunks = (len(weights_bytes) + CHUNK_SIZE - 1) // CHUNK_SIZE
|
|
733
765
|
|
|
766
|
+
# Debug: show target peer address
|
|
767
|
+
print(f" 🎯 Target: {target_node_id} @ {peer_info.peer.address}")
|
|
768
|
+
|
|
734
769
|
logger.info(
|
|
735
770
|
f"[NET] Sending chunked model to {target_node_id} "
|
|
736
771
|
f"(transfer={transfer_id[:8]}..., size={len(weights_bytes)} bytes, chunks={total_chunks})"
|
|
@@ -756,10 +791,15 @@ class GossipLearningCommunity(Community):
|
|
|
756
791
|
|
|
757
792
|
self.ez_send(peer_info.peer, chunk_payload)
|
|
758
793
|
|
|
759
|
-
#
|
|
760
|
-
|
|
794
|
+
# Progress logging every 50 chunks (with 10KB chunks, we have ~230 chunks)
|
|
795
|
+
if (i + 1) % 50 == 0 or i == total_chunks - 1:
|
|
796
|
+
progress = (i + 1) / total_chunks * 100
|
|
797
|
+
print(f" 📦 Chunk {i + 1}/{total_chunks} ({progress:.0f}%)")
|
|
798
|
+
|
|
799
|
+
# Rate limiting: 200ms delay between chunks
|
|
800
|
+
# Using asyncio.sleep so event loop can process incoming packets
|
|
761
801
|
if i < total_chunks - 1: # Don't sleep after the last chunk
|
|
762
|
-
|
|
802
|
+
await asyncio.sleep(0.2)
|
|
763
803
|
|
|
764
804
|
logger.info(f"[NET] Sent {total_chunks} chunks to {target_node_id}")
|
|
765
805
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: quinkgl
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.16
|
|
4
4
|
Summary: A decentralized gossip learning framework for P2P edge intelligence
|
|
5
5
|
Author-email: Ali Seyhan <aliseyhan@posta.mu.edu.tr>, Baki Turhan <bakiturhan@posta.mu.edu.tr>
|
|
6
6
|
Project-URL: Homepage, https://github.com/aliseyhann/QuinkGL-Gossip-Learning-Framework
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|