use super::generated::{
cohere_decoder_first, cohere_decoder_first_weights, cohere_decoder_next,
cohere_decoder_next_weights, cohere_encoder, cohere_encoder_weights,
};
use super::{array3, array4, guard, ints, onnx, tensor3, tensor4, vec_f32};
use crate::error::{Error, Result};
use crate::execution::ExecutionProvider;
use crate::model_cohere::CoherePastKv;
use burn::tensor::{Device, Tensor};
use ndarray::{Array3, ArrayView3};
use std::path::Path;
use std::sync::Arc;
pub(crate) struct CohereEncoder {
model: cohere_encoder::Model,
device: Device,
}
impl CohereEncoder {
pub(crate) fn load(path: &Path, provider: ExecutionProvider) -> Result<Self> {
let device = super::device(provider)?;
let file = onnx::OnnxFile::open(path)?;
let mut model = guard("allocating the model", || {
cohere_encoder::Model::new(&device)
})?;
file.load(&mut model, cohere_encoder_weights::WEIGHTS)?;
Ok(Self { model, device })
}
pub(crate) fn run(&self, features: ArrayView3<f32>) -> Result<Array3<f32>> {
guard("running the encoder", || {
array3(self.model.forward(tensor3(features, &self.device)))
})?
}
}
pub(crate) struct CohereDecoder {
first: cohere_decoder_first::Model,
next: cohere_decoder_next::Model,
device: Device,
}
type Step = (Vec<f32>, CoherePastKv);
impl CohereDecoder {
pub(crate) fn load(path: &Path, provider: ExecutionProvider) -> Result<Self> {
let device = super::device(provider)?;
let file = onnx::OnnxFile::open(path)?;
let mut first = guard("allocating the model", || {
cohere_decoder_first::Model::new(&device)
})?;
file.load(&mut first, cohere_decoder_first_weights::WEIGHTS)?;
let next = guard("allocating the model", || {
cohere_decoder_next::Model::new(&device)
})?;
let next = guard("sharing the decoder weights", || {
onnx::share_weights(
&first,
cohere_decoder_first_weights::WEIGHTS,
next,
cohere_decoder_next_weights::WEIGHTS,
)
})??;
Ok(Self {
first,
next,
device,
})
}
pub(crate) fn first_step(&self, tokens: &[i64], encoder: ArrayView3<f32>) -> Result<Step> {
let d = &self.device;
let n = tokens.len();
guard("running the decoder", || {
let (logits, rest) = split_first(self.first.forward(
ints(tokens.to_vec(), [1, n], d),
ints(vec![1; n], [1, n], d),
ints((0..n as i64).collect(), [1, n], d),
1,
tensor3(encoder, d),
));
let (mut decoder_k, mut decoder_v) = (Vec::new(), Vec::new());
let (mut encoder_k, mut encoder_v) = (Vec::new(), Vec::new());
for [dk, dv, ek, ev] in rest {
decoder_k.push(array4(dk)?);
decoder_v.push(array4(dv)?);
encoder_k.push(array4(ek)?);
encoder_v.push(array4(ev)?);
}
let cache = CoherePastKv {
decoder_k,
decoder_v,
encoder_k: Arc::new(encoder_k),
encoder_v: Arc::new(encoder_v),
};
Ok((vec_f32(logits)?, cache))
})?
}
pub(crate) fn next_step(&self, token: i64, past: &CoherePastKv) -> Result<Step> {
let d = &self.device;
let past_len = past.past_decoder_len();
if past_len == 0 {
return Err(Error::Model(
"Cohere decoder: a later step needs the first step's cache".into(),
));
}
let cache = |layer: usize| {
[
tensor4(past.decoder_k[layer].view(), d),
tensor4(past.decoder_v[layer].view(), d),
tensor4(past.encoder_k[layer].view(), d),
tensor4(past.encoder_v[layer].view(), d),
]
};
guard("running the decoder", || {
let [k0, v0, ek0, ev0] = cache(0);
let [k1, v1, ek1, ev1] = cache(1);
let [k2, v2, ek2, ev2] = cache(2);
let [k3, v3, ek3, ev3] = cache(3);
let [k4, v4, ek4, ev4] = cache(4);
let [k5, v5, ek5, ev5] = cache(5);
let [k6, v6, ek6, ev6] = cache(6);
let [k7, v7, ek7, ev7] = cache(7);
let (logits, k0, v0, k1, v1, k2, v2, k3, v3, k4, v4, k5, v5, k6, v6, k7, v7) =
self.next.forward(
ints(vec![token], [1, 1], d),
ints(vec![1; past_len + 1], [1, past_len + 1], d),
ints(vec![past_len as i64], [1, 1], d),
1,
k0,
v0,
ek0,
ev0,
k1,
v1,
ek1,
ev1,
k2,
v2,
ek2,
ev2,
k3,
v3,
ek3,
ev3,
k4,
v4,
ek4,
ev4,
k5,
v5,
ek5,
ev5,
k6,
v6,
ek6,
ev6,
k7,
v7,
ek7,
ev7,
);
let mut cache = CoherePastKv {
decoder_k: Vec::with_capacity(8),
decoder_v: Vec::with_capacity(8),
encoder_k: Arc::clone(&past.encoder_k),
encoder_v: Arc::clone(&past.encoder_v),
};
for (k, v) in [
(k0, v0),
(k1, v1),
(k2, v2),
(k3, v3),
(k4, v4),
(k5, v5),
(k6, v6),
(k7, v7),
] {
cache.decoder_k.push(array4(k)?);
cache.decoder_v.push(array4(v)?);
}
Ok((vec_f32(logits)?, cache))
})?
}
}
#[allow(clippy::type_complexity)]
fn split_first(
out: (
Tensor<3>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
Tensor<4>,
),
) -> (Tensor<3>, Vec<[Tensor<4>; 4]>) {
let (
logits,
a0,
a1,
a2,
a3,
b0,
b1,
b2,
b3,
c0,
c1,
c2,
c3,
d0,
d1,
d2,
d3,
e0,
e1,
e2,
e3,
f0,
f1,
f2,
f3,
g0,
g1,
g2,
g3,
h0,
h1,
h2,
h3,
) = out;
let layers = vec![
[a0, a1, a2, a3],
[b0, b1, b2, b3],
[c0, c1, c2, c3],
[d0, d1, d2, d3],
[e0, e1, e2, e3],
[f0, f1, f2, f3],
[g0, g1, g2, g3],
[h0, h1, h2, h3],
];
(logits, layers)
}