Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added depth.pfm
Binary file not shown.
Binary file added depth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 4 additions & 4 deletions src/dino_backbone.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,8 +167,8 @@ bool DinoBackbone::forward(const std::vector<float>& input_chw, int H, int W,
// --- host post-process matching get_intermediate_layers (width == 2*embed) ---
// feat = cat([local_x, vit_norm(x)]) over channels, patches 1..256 -> [256,1536]
// cam = cat([local_x[token0], x[token0]]) RAW (no norm) -> [1536]
ggml_tensor* nw = ml_.tensor("vit.norm.weight");
ggml_tensor* nb = ml_.tensor("vit.norm.bias");
ggml_tensor* nw = ml_.host_tensor("vit.norm.weight");
ggml_tensor* nb = ml_.host_tensor("vit.norm.bias");
const float* nwp=(const float*)nw->data;
const float* nbp=(const float*)nb->data;
auto layernorm_host=[&](const float* row)->std::vector<float>{
Expand Down Expand Up @@ -566,8 +566,8 @@ bool DinoBackbone::forward_mv_ordered(const std::vector<std::vector<float>>& vie
if (!ok) return false;

// Host post-process per view (matches the S=1 path, repeated per view-slice).
ggml_tensor* nw = ml_.tensor("vit.norm.weight");
ggml_tensor* nb = ml_.tensor("vit.norm.bias");
ggml_tensor* nw = ml_.host_tensor("vit.norm.weight");
ggml_tensor* nb = ml_.host_tensor("vit.norm.bias");
const float* nwp=(const float*)nw->data;
const float* nbp=(const float*)nb->data;
auto layernorm_host=[&](const float* row)->std::vector<float>{
Expand Down
37 changes: 28 additions & 9 deletions src/model_loader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,24 @@ static bool g_gpu_mode = false;
void set_gpu_mode(bool on){ g_gpu_mode = on; }
bool gpu_mode(){ return g_gpu_mode; }

// Weights read directly on the HOST via ->data during graph build (they feed
// host-computed graph INPUTS, not graph nodes), so they MUST stay in
// Weights read directly on the HOST via ->data during graph build feed
// host-computed graph INPUTS (not graph nodes), so they MUST stay in
// host-accessible memory and are never mirrored to the device:
// - "vit.pos_embed" : host bicubic interp in DinoBackbone::interp_pos_embed
// - "vit.camera_token": host camera-token inject in DinoBackbone::forward*
// - "vit.norm.weight" / "vit.norm.bias": host post-norm in DinoBackbone
// (The metric branch aliases m_vit.* -> vit.* so the same names apply.)
static bool is_host_read_tensor(const std::string& name) {
return name == "vit.pos_embed" || name == "vit.camera_token" ||
name == "vit.norm.weight" || name == "vit.norm.bias";
static bool is_host_only_tensor(const std::string& name) {
return name == "vit.pos_embed" || name == "vit.camera_token";
}

// Weights that are DUAL-USE: real ggml graph operands in the fused path
// (DinoBackbone::build_feats_graph -> layernorm(x, vit.norm.{w,b})), AND read
// directly on the host in the unfused / multi-view path (layernorm_host). These
// must be mirrored to the device so the graph has a valid backend buffer (else
// the Metal encoder derefs a NULL buffer and segfaults), while their host
// originals are preserved for the host readers via ModelLoader::host_tensor().
static bool is_host_also_tensor(const std::string& name) {
return name == "vit.norm.weight" || name == "vit.norm.bias";
}

static uint32_t kv_u32(gguf_context* g, const char* k, uint32_t d=0){
Expand Down Expand Up @@ -192,10 +200,14 @@ bool ModelLoader::offload_weights(Backend& be){
std::unordered_map<std::string, ggml_tensor*> newmap; newmap.reserve(n);
size_t n_dev = 0;
for (auto& kv : tensors_) {
if (is_host_read_tensor(kv.first)) {
if (is_host_only_tensor(kv.first)) {
newmap.emplace(kv.first, kv.second); // keep host tensor as-is
continue;
}
// Dual-use weights: preserve the host original for host_tensor() reads,
// then fall through to mirror them onto the device for the graph.
if (is_host_also_tensor(kv.first))
host_tensors_.emplace(kv.first, kv.second);
ggml_tensor* s = kv.second;
auto it = src2dev.find(s);
if (it != src2dev.end()) { // alias of an already-mirrored tensor
Expand All @@ -214,8 +226,15 @@ bool ModelLoader::offload_weights(Backend& be){
for (auto& pr : ups)
ggml_backend_tensor_set(pr.first, pr.second, 0, ggml_nbytes(pr.first));
tensors_.swap(newmap); // graphs now reference the device-resident weights
DA_LOG("offload_weights: %zu weights -> %s (%zu host-read tensors kept on CPU)",
n_dev, be.device_name().c_str(), (size_t)4);
DA_LOG("offload_weights: %zu weights -> %s (%zu host-only tensors kept on CPU, "
"%zu dual-use weights mirrored + host-preserved)",
n_dev, be.device_name().c_str(), (size_t)2, host_tensors_.size());
return true;
}

ggml_tensor* ModelLoader::host_tensor(const std::string& name) const {
auto it = host_tensors_.find(name);
if (it != host_tensors_.end()) return it->second; // preserved host original
return tensor(name); // CPU path: never offloaded
}
} // namespace da
7 changes: 7 additions & 0 deletions src/model_loader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,19 @@ class ModelLoader {
bool load(const std::string& path);
const Config& config() const { return cfg_; }
ggml_tensor* tensor(const std::string& name) const;
// Host-resident copy of a dual-use weight (e.g. vit.norm.{weight,bias}) that is
// BOTH a graph operand (device-resident after offload) AND read directly on the
// host (layernorm_host). Falls back to tensor() when not offloading. Use this at
// every `->data` read site so it stays valid on GPU backends.
ggml_tensor* host_tensor(const std::string& name) const;
bool offload_weights(Backend& be);
private:
Config cfg_;
gguf_context* gguf_ = nullptr;
ggml_context* ctx_ = nullptr;
std::unordered_map<std::string, ggml_tensor*> tensors_;
// Preserved host originals of dual-use weights mirrored to the device.
std::unordered_map<std::string, ggml_tensor*> host_tensors_;
ggml_context* device_ctx_ = nullptr;
ggml_backend_buffer* gpu_buf_ = nullptr;
};
Expand Down