red-candle 1.8.0.pre3-aarch64-linux → 1.8.2-aarch64-linux
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.
- checksums.yaml +4 -4
- data/README.md +4 -0
- data/Rakefile +26 -7
- data/ext/candle/src/ruby/embedding_model.rs +22 -6
- data/lib/candle/3.1/candle.so +0 -0
- data/lib/candle/3.2/candle.so +0 -0
- data/lib/candle/3.3/candle.so +0 -0
- data/lib/candle/3.4/candle.so +0 -0
- data/lib/candle/4.0/candle.so +0 -0
- data/lib/candle/embedding_model.rb +7 -4
- data/lib/candle/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d5e21bb0c8bd8b2ee1742ce7f1d4ba4105fe8472345e5173f001abeb899d2097
|
|
4
|
+
data.tar.gz: 291bef82a1050bb76bd848feb38902a603b4ecb3cfa507a61320dcb2bbeee18c
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58aee435bf605260b6a71a9458fec999ebae00c60d5105d4d2be3fa1fd532a5c9d990b980e69dffcba3ecd20a63dd463dfca65bd4d468d188206bdf6010d95fc
|
|
7
|
+
data.tar.gz: d653d24ceb94edf532e1562f5dffa28ab13fb614577ae7f88ac024d5bcd356ea6c6aa7e67d1f71b91a7d13debb570be051b2fc33d5575099b86b029f9c75947e
|
data/README.md
CHANGED
|
@@ -107,6 +107,10 @@ device = Candle::Device.cpu # or Candle::Device.metal, Candle::Device.cuda
|
|
|
107
107
|
model = Candle::EmbeddingModel.from_pretrained("jinaai/jina-embeddings-v2-base-en", device: device)
|
|
108
108
|
embedding = model.embedding("Hi there!")
|
|
109
109
|
|
|
110
|
+
# Cap input length (in tokens) to cut memory; longer inputs are truncated.
|
|
111
|
+
# JinaBERT otherwise reserves ~3.2 GB for its full 8192-token context.
|
|
112
|
+
model = Candle::EmbeddingModel.from_pretrained(max_length: 512)
|
|
113
|
+
|
|
110
114
|
# Reranker also supports device selection
|
|
111
115
|
reranker = Candle::Reranker.from_pretrained("cross-encoder/ms-marco-MiniLM-L-12-v2", device: device)
|
|
112
116
|
results = reranker.rerank("query", ["doc1", "doc2", "doc3"])
|
data/Rakefile
CHANGED
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
require "bundler/gem_tasks"
|
|
4
4
|
require "rake/extensiontask"
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
# rspec is a dev-only dependency. The rb-sys-dock cross-compile container installs
|
|
7
|
+
# the RUNTIME bundle only, so this require is absent there — guard it so the Rakefile
|
|
8
|
+
# (and therefore the `native:<platform>` cross tasks) still loads in a build-only env.
|
|
9
|
+
begin
|
|
10
|
+
require "rspec/core/rake_task"
|
|
11
|
+
RSPEC_AVAILABLE = true
|
|
12
|
+
rescue LoadError
|
|
13
|
+
RSPEC_AVAILABLE = false
|
|
14
|
+
end
|
|
6
15
|
|
|
7
16
|
task default: :spec
|
|
8
17
|
|
|
@@ -90,18 +99,28 @@ desc "Run Rust tests with coverage (alias)"
|
|
|
90
99
|
task "coverage:rust" => "rust:coverage:html"
|
|
91
100
|
|
|
92
101
|
# RSpec tasks
|
|
93
|
-
|
|
94
|
-
RSpec
|
|
95
|
-
|
|
102
|
+
if RSPEC_AVAILABLE
|
|
103
|
+
desc "Run RSpec tests"
|
|
104
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
|
105
|
+
t.rspec_opts = "--format progress"
|
|
106
|
+
end
|
|
107
|
+
else
|
|
108
|
+
desc "spec (rspec unavailable here)"
|
|
109
|
+
task(:spec) { abort "rspec is a dev dependency — not available in this environment" }
|
|
96
110
|
end
|
|
97
111
|
|
|
98
112
|
# Add compile as a dependency for spec task
|
|
99
113
|
task spec: :compile
|
|
100
114
|
|
|
101
115
|
namespace :spec do
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
116
|
+
if RSPEC_AVAILABLE
|
|
117
|
+
desc "Run RSpec tests with all devices"
|
|
118
|
+
RSpec::Core::RakeTask.new(:device) do |t|
|
|
119
|
+
t.rspec_opts = "--format documentation --tag device"
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
desc "spec:device (rspec unavailable here)"
|
|
123
|
+
task(:device) { abort "rspec is a dev dependency — not available in this environment" }
|
|
105
124
|
end
|
|
106
125
|
|
|
107
126
|
desc "Run RSpec tests with coverage"
|
|
@@ -72,10 +72,11 @@ pub struct EmbeddingModelInner {
|
|
|
72
72
|
model: Option<EmbeddingModelVariant>,
|
|
73
73
|
tokenizer: Option<TokenizerWrapper>,
|
|
74
74
|
embedding_size: Option<usize>,
|
|
75
|
+
max_length: Option<usize>,
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
impl EmbeddingModel {
|
|
78
|
-
pub fn new(model_id: Option<String>, tokenizer: Option<String>, device: Option<Device>, model_type: Option<String>, embedding_size: Option<usize>) -> Result<Self> {
|
|
79
|
+
pub fn new(model_id: Option<String>, tokenizer: Option<String>, device: Option<Device>, model_type: Option<String>, embedding_size: Option<usize>, max_length: Option<usize>) -> Result<Self> {
|
|
79
80
|
let device = device.unwrap_or(Device::best()).as_device()?;
|
|
80
81
|
let model_type = model_type
|
|
81
82
|
.and_then(|mt| EmbeddingModelType::from_string(&mt))
|
|
@@ -86,14 +87,15 @@ impl EmbeddingModel {
|
|
|
86
87
|
tokenizer_id: tokenizer.clone(),
|
|
87
88
|
model_type: Some(model_type),
|
|
88
89
|
model: match model_id.as_ref() {
|
|
89
|
-
Some(id) => Some(Self::build_embedding_model(id, device, model_type, embedding_size)?),
|
|
90
|
+
Some(id) => Some(Self::build_embedding_model(id, device, model_type, embedding_size, max_length)?),
|
|
90
91
|
None => None
|
|
91
92
|
},
|
|
92
93
|
tokenizer: match tokenizer {
|
|
93
|
-
Some(tid) => Some(Self::build_tokenizer(tid)?),
|
|
94
|
+
Some(tid) => Some(Self::build_tokenizer(tid, max_length)?),
|
|
94
95
|
None => None
|
|
95
96
|
},
|
|
96
97
|
embedding_size,
|
|
98
|
+
max_length,
|
|
97
99
|
}))
|
|
98
100
|
}
|
|
99
101
|
|
|
@@ -177,7 +179,7 @@ impl EmbeddingModel {
|
|
|
177
179
|
}
|
|
178
180
|
}
|
|
179
181
|
|
|
180
|
-
fn build_embedding_model(model_id: &str, device: CoreDevice, model_type: EmbeddingModelType, embedding_size: Option<usize>) -> Result<EmbeddingModelVariant> {
|
|
182
|
+
fn build_embedding_model(model_id: &str, device: CoreDevice, model_type: EmbeddingModelType, embedding_size: Option<usize>, max_length: Option<usize>) -> Result<EmbeddingModelVariant> {
|
|
181
183
|
use hf_hub::{api::sync::Api, Repo, RepoType};
|
|
182
184
|
let api = Api::new().map_err(wrap_hf_err)?;
|
|
183
185
|
let repo = Repo::new(model_id.to_string(), RepoType::Model);
|
|
@@ -194,6 +196,11 @@ impl EmbeddingModel {
|
|
|
194
196
|
let final_emb_dim = Self::resolve_embedding_size(Path::new(&model_path), embedding_size)?;
|
|
195
197
|
let mut config = JinaConfig::v2_base();
|
|
196
198
|
config.hidden_size = final_emb_dim;
|
|
199
|
+
// JinaBERT precomputes an ALiBi bias of heads x len x len floats
|
|
200
|
+
// (3.2 GB at the default 8192), so size it to the inputs we accept.
|
|
201
|
+
if let Some(max_length) = max_length {
|
|
202
|
+
config.max_position_embeddings = max_length;
|
|
203
|
+
}
|
|
197
204
|
let vb = unsafe {
|
|
198
205
|
VarBuilder::from_mmaped_safetensors(&[model_path], CoreDType::F32, &device)
|
|
199
206
|
.map_err(wrap_candle_err)?
|
|
@@ -268,7 +275,7 @@ impl EmbeddingModel {
|
|
|
268
275
|
}
|
|
269
276
|
}
|
|
270
277
|
|
|
271
|
-
fn build_tokenizer(tokenizer_id: String) -> Result<TokenizerWrapper> {
|
|
278
|
+
fn build_tokenizer(tokenizer_id: String, max_length: Option<usize>) -> Result<TokenizerWrapper> {
|
|
272
279
|
use hf_hub::{api::sync::Api, Repo, RepoType};
|
|
273
280
|
let tokenizer_path = Api::new()
|
|
274
281
|
.map_err(wrap_hf_err)?
|
|
@@ -282,6 +289,10 @@ impl EmbeddingModel {
|
|
|
282
289
|
.map_err(wrap_std_err)?;
|
|
283
290
|
|
|
284
291
|
let tokenizer = TokenizerLoader::with_padding(tokenizer, None);
|
|
292
|
+
let tokenizer = match max_length {
|
|
293
|
+
Some(max_length) => TokenizerLoader::with_truncation(tokenizer, max_length),
|
|
294
|
+
None => tokenizer,
|
|
295
|
+
};
|
|
285
296
|
Ok(TokenizerWrapper::new(tokenizer))
|
|
286
297
|
}
|
|
287
298
|
|
|
@@ -451,6 +462,11 @@ impl EmbeddingModel {
|
|
|
451
462
|
if let Some(size) = self.0.embedding_size {
|
|
452
463
|
hash.aset("embedding_size", size)?;
|
|
453
464
|
}
|
|
465
|
+
|
|
466
|
+
// Add max_length
|
|
467
|
+
if let Some(max_length) = self.0.max_length {
|
|
468
|
+
hash.aset("max_length", max_length)?;
|
|
469
|
+
}
|
|
454
470
|
|
|
455
471
|
Ok(hash)
|
|
456
472
|
}
|
|
@@ -459,7 +475,7 @@ impl EmbeddingModel {
|
|
|
459
475
|
pub fn init(rb_candle: RModule) -> Result<()> {
|
|
460
476
|
let ruby = Ruby::get().unwrap();
|
|
461
477
|
let rb_embedding_model = rb_candle.define_class("EmbeddingModel", ruby.class_object())?;
|
|
462
|
-
rb_embedding_model.define_singleton_method("_create", function!(EmbeddingModel::new,
|
|
478
|
+
rb_embedding_model.define_singleton_method("_create", function!(EmbeddingModel::new, 6))?;
|
|
463
479
|
// Expose embedding with an optional pooling_method argument (default: "pooled")
|
|
464
480
|
rb_embedding_model.define_method("_embedding", method!(EmbeddingModel::embedding, 2))?;
|
|
465
481
|
rb_embedding_model.define_method("embeddings", method!(EmbeddingModel::embeddings, 1))?;
|
data/lib/candle/3.1/candle.so
CHANGED
|
Binary file
|
data/lib/candle/3.2/candle.so
CHANGED
|
Binary file
|
data/lib/candle/3.3/candle.so
CHANGED
|
Binary file
|
data/lib/candle/3.4/candle.so
CHANGED
|
Binary file
|
data/lib/candle/4.0/candle.so
CHANGED
|
Binary file
|
|
@@ -15,8 +15,9 @@ module Candle
|
|
|
15
15
|
# @param tokenizer [String, nil] The tokenizer to use (defaults to using the model's tokenizer)
|
|
16
16
|
# @param model_type [String, nil] The type of embedding model (auto-detected if nil)
|
|
17
17
|
# @param embedding_size [Integer, nil] Override for the embedding size (optional)
|
|
18
|
+
# @param max_length [Integer, nil] Longest input in tokens; longer inputs are truncated (optional)
|
|
18
19
|
# @return [EmbeddingModel] A new EmbeddingModel instance
|
|
19
|
-
def self.from_pretrained(model_id = DEFAULT_MODEL_PATH, device: Candle::Device.best, tokenizer: nil, model_type: nil, embedding_size: nil)
|
|
20
|
+
def self.from_pretrained(model_id = DEFAULT_MODEL_PATH, device: Candle::Device.best, tokenizer: nil, model_type: nil, embedding_size: nil, max_length: nil)
|
|
20
21
|
# Auto-detect model type based on model_id if not provided
|
|
21
22
|
if model_type.nil?
|
|
22
23
|
model_type = case model_id.downcase
|
|
@@ -34,7 +35,7 @@ module Candle
|
|
|
34
35
|
# Use model_id as tokenizer if not specified (usually what you want)
|
|
35
36
|
tokenizer_id = tokenizer || model_id
|
|
36
37
|
|
|
37
|
-
_create(model_id, tokenizer_id, device, model_type, embedding_size)
|
|
38
|
+
_create(model_id, tokenizer_id, device, model_type, embedding_size, max_length)
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
# Constructor for creating a new EmbeddingModel with optional parameters
|
|
@@ -44,13 +45,15 @@ module Candle
|
|
|
44
45
|
# @param device [Candle::Device, Candle::Device.cpu] The device to use for computation
|
|
45
46
|
# @param model_type [String, nil] The type of embedding model to use
|
|
46
47
|
# @param embedding_size [Integer, nil] Override for the embedding size (optional)
|
|
48
|
+
# @param max_length [Integer, nil] Longest input in tokens; longer inputs are truncated (optional)
|
|
47
49
|
def self.new(model_path: DEFAULT_MODEL_PATH,
|
|
48
50
|
tokenizer_path: DEFAULT_TOKENIZER_PATH,
|
|
49
51
|
device: Candle::Device.best,
|
|
50
52
|
model_type: DEFAULT_EMBEDDING_MODEL_TYPE,
|
|
51
|
-
embedding_size: nil
|
|
53
|
+
embedding_size: nil,
|
|
54
|
+
max_length: nil)
|
|
52
55
|
$stderr.puts "[DEPRECATION] `EmbeddingModel.new` is deprecated. Please use `EmbeddingModel.from_pretrained` instead."
|
|
53
|
-
_create(model_path, tokenizer_path, device, model_type, embedding_size)
|
|
56
|
+
_create(model_path, tokenizer_path, device, model_type, embedding_size, max_length)
|
|
54
57
|
end
|
|
55
58
|
# Returns the embedding for a string using the specified pooling method.
|
|
56
59
|
# @param str [String] The input text
|
data/lib/candle/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: red-candle
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.8.
|
|
4
|
+
version: 1.8.2
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Christopher Petersen
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2026-
|
|
12
|
+
date: 2026-10-30 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: rb_sys
|