Files
aha/src/models/deepseek_ocr/model.rs
T

384 lines
11 KiB
Rust
Raw Normal View History

2025-11-09 15:40:29 +08:00
use anyhow::{Ok, Result};
2025-11-13 00:33:27 +08:00
use candle_core::{D, IndexOp, Tensor};
2025-11-09 15:40:29 +08:00
use candle_nn::{
2025-11-13 00:33:27 +08:00
Activation, Conv2d, Conv2dConfig, Init, LayerNorm, LayerNormConfig, Linear, Module, VarBuilder,
conv2d, layer_norm, linear, linear_no_bias,
2025-11-09 15:40:29 +08:00
};
2025-11-13 00:33:27 +08:00
use crate::{
models::{common::eager_attention_forward, deepseek_ocr::config::DeepseekOCRConfig},
utils::tensor_utils::{index_select_2d, interpolate_linear},
};
2025-11-09 15:40:29 +08:00
pub struct PatchEmbed {
proj: Conv2d,
}
impl PatchEmbed {
pub fn new(
vb: VarBuilder,
in_chans: usize,
embed_dim: usize,
kernel_size: usize,
stride: usize,
padding: usize,
) -> Result<Self> {
let cfg = Conv2dConfig {
padding,
stride,
dilation: 1,
groups: 1,
cudnn_fwd_algo: None,
};
let proj = conv2d(in_chans, embed_dim, kernel_size, cfg, vb.pp("proj"))?;
Ok(Self { proj })
}
pub fn forward(&self, xs: &Tensor) -> Result<Tensor> {
let xs = self.proj.forward(xs)?;
let xs = xs.permute((0, 2, 3, 1))?;
Ok(xs)
}
}
pub struct Attention {
num_heads: usize,
head_dim: usize,
qkv: Linear,
proj: Linear,
scaling: f64,
use_rel_pos: bool,
rel_pos_h: Option<Tensor>,
rel_pos_w: Option<Tensor>,
}
impl Attention {
pub fn new(
vb: VarBuilder,
dim: usize,
num_heads: usize,
qkv_bias: bool,
use_rel_pos: bool,
input_size: Option<(usize, usize)>,
) -> Result<Self> {
let head_dim = dim / num_heads;
let scaling = 1.0 / (head_dim as f64).sqrt();
let qkv = if qkv_bias {
linear(dim, dim * 3, vb.pp("qkv"))?
} else {
linear_no_bias(dim, dim * 3, vb.pp("qkv"))?
};
let proj = linear(dim, dim, vb.pp("proj"))?;
let mut rel_pos_h = None;
let mut rel_pos_w = None;
if use_rel_pos {
if input_size.is_none() {
return Err(anyhow::anyhow!(
"Input size must be provided if using relative positional encoding."
));
}
let input_size = input_size.unwrap();
let h_len = 2 * input_size.0 - 1;
let w_len = 2 * input_size.1 - 1;
rel_pos_h = Some(vb.get_with_hints((h_len, head_dim), "rel_pos_h", Init::Const(0.))?);
rel_pos_w = Some(vb.get_with_hints((w_len, head_dim), "rel_pos_w", Init::Const(0.))?);
}
Ok(Self {
num_heads,
head_dim,
qkv,
proj,
scaling,
use_rel_pos,
rel_pos_h,
rel_pos_w,
})
}
2025-11-13 00:33:27 +08:00
fn get_rel_pos(&self, q_size: usize, k_size: usize, rel_pos: &Tensor) -> Result<Tensor> {
let max_rel_dist = 2 * std::cmp::max(q_size, k_size) - 1;
let rel_pos_resized = if rel_pos.dim(0)? != max_rel_dist {
let rel_pos = rel_pos
.to_dtype(candle_core::DType::F32)?
.t()?
.unsqueeze(0)?
.contiguous()?;
let rel_pos_resized = interpolate_linear(&rel_pos, max_rel_dist, None)?;
let rel_pos_resized = rel_pos_resized
.squeeze(0)?
.t()?
.contiguous()?
.to_dtype(rel_pos.dtype())?;
rel_pos_resized
} else {
rel_pos.clone()
};
let q_coords = Tensor::arange(0 as f32, q_size as f32, rel_pos.device())?
.unsqueeze(D::Minus1)?
.affine((k_size as f64 / q_size as f64).max(1.0), 0.0)?;
let k_coords = Tensor::arange(0 as f32, k_size as f32, rel_pos.device())?
.unsqueeze(0)?
.affine((q_size as f64 / k_size as f64).max(1.0), 0.0)?;
let relative_coords = q_coords
.broadcast_sub(&k_coords)?
.affine(1.0, (k_size - 1) as f64)?
.affine((q_size as f64 / k_size as f64).max(1.0), 0.0)?;
let relative_coords = relative_coords
.to_dtype(candle_core::DType::U32)?
.contiguous()?;
let rel_pos_resized = rel_pos_resized.contiguous()?;
let res = index_select_2d(&rel_pos_resized, &relative_coords)?;
Ok(res)
}
2025-11-09 15:40:29 +08:00
2025-11-13 00:33:27 +08:00
fn add_decomposed_rel_pos(
&self,
q: &Tensor,
rel_pos_h: &Tensor,
rel_pos_w: &Tensor,
q_size: (usize, usize),
k_size: (usize, usize),
) -> Result<(Tensor, Tensor)> {
let (q_h, q_w) = q_size;
let (k_h, k_w) = k_size;
let rh = self.get_rel_pos(q_h, k_h, rel_pos_h)?; // (h, w, dim)
let rh = rh.t()?; // (h, dim, w)
let rw = self.get_rel_pos(q_w, k_w, rel_pos_w)?;
let rw = rw.t()?;
let (b, _, dim) = q.dims3()?;
let r_q = q.reshape((b, q_h, q_w, dim))?;
let rel_h = r_q.broadcast_matmul(&rh)?;
let rel_w = r_q.broadcast_matmul(&rw)?;
let rel_h = rel_h
.unsqueeze(D::Minus1)?
.reshape((b, q_h * q_w, k_h, 1))?;
let rel_w = rel_w
.unsqueeze(D::Minus2)?
.reshape((b, q_h * q_w, 1, k_w))?;
Ok((rel_h, rel_w))
}
2025-11-09 15:40:29 +08:00
2025-11-13 00:33:27 +08:00
pub fn forward(&mut self, xs: &Tensor) -> Result<Tensor> {
let (b, h, w, _) = xs.dims4()?;
// (3, B, n_head, h*w, head_dim)
let qkv = self
.qkv
.forward(xs)?
.reshape((b, h * w, 3, self.num_heads, ()))?
.permute((2, 0, 3, 1, 4))?
.contiguous()?;
let query_states = qkv.i(0)?.contiguous()?;
let key_states = qkv.i(1)?.contiguous()?;
let value_states = qkv.i(2)?.contiguous()?;
let xs = if self.use_rel_pos {
let q_reshape = query_states.reshape((b * self.num_heads, h * w, ()))?;
let (rel_h, rel_w) = self.add_decomposed_rel_pos(
&q_reshape,
self.rel_pos_h.as_ref().unwrap(),
self.rel_pos_w.as_ref().unwrap(),
(h, w),
(h, w),
)?;
let (_, rel_h_dim1, rel_h_dim2, rel_h_dim3) = rel_h.dims4()?;
let rel_h = rel_h.reshape((b, self.num_heads, rel_h_dim1, rel_h_dim2, rel_h_dim3))?;
let (_, rel_w_dim1, rel_w_dim2, rel_w_dim3) = rel_w.dims4()?;
let rel_w = rel_w.reshape((b, self.num_heads, rel_w_dim1, rel_w_dim2, rel_w_dim3))?;
let attn_bias = rel_h.broadcast_add(&rel_w)?.reshape((
b,
self.num_heads,
rel_h_dim1,
rel_h_dim2 * rel_w_dim3,
))?;
let xs = eager_attention_forward(
&query_states,
&key_states,
&value_states,
None,
Some(&attn_bias),
self.scaling,
)?;
xs
} else {
eager_attention_forward(
&query_states,
&key_states,
&value_states,
None,
None,
self.scaling,
)?
};
// (b, h*w, n_head, dim)
let xs = xs.reshape((b, h * w, ()))?.reshape((b, h, w, ()))?;
let xs = self.proj.forward(&xs)?;
Ok(xs)
}
}
pub struct MLPBlock {
linear1: Linear,
linear2: Linear,
act: Activation,
}
impl MLPBlock {
pub fn new(
vb: VarBuilder,
embedding_dim: usize,
mlp_dim: usize,
act: Activation,
) -> Result<Self> {
let linear1 = linear(embedding_dim, mlp_dim, vb.pp("lin1"))?;
let linear2 = linear(mlp_dim, embedding_dim, vb.pp("lin2"))?;
Ok(Self {
linear1,
linear2,
act,
})
}
pub fn forward(&self, xs: &Tensor) -> Result<Tensor> {
let xs = xs
.apply(&self.linear1)?
.apply(&self.act)?
.apply(&self.linear2)?;
Ok(xs)
}
2025-11-09 15:40:29 +08:00
}
pub struct Block {
norm1: LayerNorm,
attn: Attention,
2025-11-13 00:33:27 +08:00
norm2: LayerNorm,
mlp: MLPBlock,
window_size: usize,
}
impl Block {
pub fn new(
vb: VarBuilder,
dim: usize,
num_heads: usize,
mlp_ratio: f32,
qkv_bias: bool,
eps: f64,
act: Activation,
use_rel_pos: bool,
rel_pos_zero_init: bool,
window_size: usize,
input_size: Option<(usize, usize)>,
) -> Result<Self> {
let ln_config = LayerNormConfig {
eps,
remove_mean: true, // true for layernorm, false for RMSNorm
affine: true, // true for with bias, false for without bias
};
let norm1 = layer_norm(dim, ln_config, vb.pp("norm1"))?;
let input_size = if window_size == 0 {
input_size
} else {
Some((window_size, window_size))
};
let attn = Attention::new(
vb.pp("attn"),
dim,
num_heads,
qkv_bias,
use_rel_pos,
input_size,
)?;
let norm2 = layer_norm(dim, ln_config, vb.pp("norm2"))?;
let mlp_dim = (dim as f32 * mlp_ratio) as usize;
let mlp = MLPBlock::new(vb.pp("mlp"), dim, mlp_dim, act)?;
Ok(Self {
norm1,
attn,
norm2,
mlp,
window_size,
})
}
pub fn window_partition(
&self,
x: &Tensor,
window_size: usize,
) -> Result<(Tensor, (usize, usize))> {
let (b, h, w, c) = x.dims4()?;
let pad_h = (window_size - h % window_size) % window_size;
let pad_w = (window_size - w % window_size) % window_size;
let x = if pad_h > 0 || pad_w > 0 {
let x = x.pad_with_zeros(1, 0, pad_h)?;
let x = x.pad_with_zeros(2, 0, pad_w)?;
x
} else {
x.clone()
};
let hp = h + pad_h;
let wp = w + pad_w;
let x = x.reshape((
b,
hp / window_size,
window_size,
wp / window_size,
window_size,
c,
))?;
let windows = x.permute((0, 1, 3, 2, 4, 5))?.contiguous()?.reshape((
(),
window_size,
window_size,
c,
))?;
Ok((windows, (hp, wp)))
}
// pub fn window_unpartition(
// &self,
// x: &Tensor,
// window_size: usize,
// pad_hw: (usize, usize),
// hw: (usize, usize),
// ) -> Result<Tensor> {
// }
// pub fn forward(&self, xs: &Tensor) -> Result<Tensor> {
// let shortcut = xs.clone();
// let xs = self.norm1.forward(xs)?;
// let xs = if self.window_size > 0 {
// let h = xs.dim(1)?;
// let w = xs.dim(2)?;
// let (x, (hp, wp)) = self.window_partition(&xs, self.window_size)?;
// let x = self.attn.forward(&x)?;
// } else {
// self.attn.forward(&xs)?
// };
// }
2025-11-09 15:40:29 +08:00
}
pub struct ImageEncoderViT {
img_size: usize,
patch_embed: PatchEmbed,
pos_embed: Option<Tensor>,
blocks: Vec<Block>,
}
pub struct VitModel {}
pub struct DeepseekV2Model {}
pub struct MlpProjector {}
pub struct DeepseekOCRModel {
config: DeepseekOCRConfig,
sam_model: ImageEncoderViT,
vision_model: VitModel,
language_model: DeepseekV2Model,
projector: MlpProjector,
embed_std: f64,
image_newline: Tensor,
view_seperator: Tensor,
lm_head: Linear,
}