static_embeddings 0.1.4 → 0.1.5
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/CHANGELOG.md +68 -0
- data/README.md +50 -23
- data/Rakefile +1 -1
- data/docs/ARCHITECTURE.md +42 -31
- data/docs/LIMITATIONS.md +12 -6
- data/docs/MODEL_AUDIT.md +85 -52
- data/ext/static_embeddings/se_embed.c +2 -1
- data/ext/static_embeddings/se_format.c +41 -4
- data/ext/static_embeddings/se_internal.h +17 -5
- data/ext/static_embeddings/se_tokenizer.c +155 -18
- data/ext/static_embeddings/se_unicode.c +1 -1
- data/ext/static_embeddings/static_embeddings.c +32 -2
- data/lib/static_embeddings/cli.rb +1 -0
- data/lib/static_embeddings/converter.rb +51 -7
- data/lib/static_embeddings/format.rb +60 -22
- data/lib/static_embeddings/paths.rb +18 -1
- data/lib/static_embeddings/reference.rb +54 -7
- data/lib/static_embeddings/safetensors.rb +178 -34
- data/lib/static_embeddings/version.rb +1 -1
- data/lib/static_embeddings.rb +3 -5
- data/tools/check_model2vec_parity.rb +85 -54
- metadata +1 -1
|
@@ -4,8 +4,7 @@ require "static_embeddings"
|
|
|
4
4
|
|
|
5
5
|
options = {
|
|
6
6
|
min_cosine: 1.0 - 1e-6,
|
|
7
|
-
max_abs: 1e-5
|
|
8
|
-
ids: true
|
|
7
|
+
max_abs: 1e-5
|
|
9
8
|
}
|
|
10
9
|
|
|
11
10
|
parser = OptionParser.new do |opts|
|
|
@@ -13,7 +12,6 @@ parser = OptionParser.new do |opts|
|
|
|
13
12
|
opts.on("--oracle PATH") { |value| options[:oracle] = value }
|
|
14
13
|
opts.on("--min-cosine N", Float) { |value| options[:min_cosine] = value }
|
|
15
14
|
opts.on("--max-abs N", Float) { |value| options[:max_abs] = value }
|
|
16
|
-
opts.on("--[no-]ids") { |value| options[:ids] = value }
|
|
17
15
|
end
|
|
18
16
|
parser.parse!(ARGV)
|
|
19
17
|
unless options[:model] && options[:oracle]
|
|
@@ -22,12 +20,18 @@ end
|
|
|
22
20
|
|
|
23
21
|
model = StaticEmbeddings.load(options[:model], verify: true)
|
|
24
22
|
payload = JSON.parse(File.read(options[:oracle], encoding: "UTF-8"))
|
|
25
|
-
|
|
26
|
-
oracle_max_length = payload.is_a?(Hash) ? payload["max_length"] : nil
|
|
23
|
+
abort "unsupported oracle schema #{payload["schema_version"].inspect}" unless payload["schema_version"] == 2
|
|
27
24
|
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
reference = payload.fetch("reference")
|
|
26
|
+
max_length = Integer(reference.fetch("max_length"))
|
|
27
|
+
if max_length != model.max_tokens
|
|
28
|
+
abort "oracle max_length=#{max_length} but model.max_tokens=#{model.max_tokens}"
|
|
30
29
|
end
|
|
30
|
+
if reference["unk_token_id"] && Integer(reference["unk_token_id"]) != model.unk_id
|
|
31
|
+
abort "oracle unk_token_id=#{reference["unk_token_id"]} but model.unk_id=#{model.unk_id}"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
rows = payload.fetch("rows")
|
|
31
35
|
|
|
32
36
|
def dot(a, b)
|
|
33
37
|
a.zip(b).sum { |x, y| x * y }
|
|
@@ -37,71 +41,98 @@ def norm(a)
|
|
|
37
41
|
Math.sqrt(a.sum { |x| x * x })
|
|
38
42
|
end
|
|
39
43
|
|
|
44
|
+
def vector_metrics(reference, got)
|
|
45
|
+
max_abs = reference.zip(got).map { |a, b| (a - b).abs }.max || 0.0
|
|
46
|
+
ref_zero = reference.all?(&:zero?)
|
|
47
|
+
got_zero = got.all?(&:zero?)
|
|
48
|
+
cosine =
|
|
49
|
+
if ref_zero && got_zero
|
|
50
|
+
1.0
|
|
51
|
+
elsif ref_zero || got_zero
|
|
52
|
+
0.0
|
|
53
|
+
else
|
|
54
|
+
dot(reference, got) / (norm(reference) * norm(got))
|
|
55
|
+
end
|
|
56
|
+
[cosine, max_abs]
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
raw_failures = []
|
|
60
|
+
usable_failures = []
|
|
61
|
+
vector_failures = []
|
|
62
|
+
invariant_failures = []
|
|
63
|
+
intentional_deviations = []
|
|
40
64
|
min_cosine = 1.0
|
|
41
65
|
max_abs_all = 0.0
|
|
42
|
-
|
|
43
|
-
id_failures = []
|
|
44
|
-
id_rows_checked = 0
|
|
66
|
+
vectors_checked = 0
|
|
45
67
|
|
|
46
68
|
rows.each_with_index do |row, i|
|
|
47
69
|
text = row.fetch("text")
|
|
48
|
-
|
|
49
|
-
ref_ids = row["token_ids"]
|
|
50
|
-
|
|
70
|
+
label = row.fetch("label", i.to_s)
|
|
51
71
|
problems = []
|
|
52
72
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
problems << "ids differ at #{first} (got #{got_ids.length}, ref #{ref_ids.length})"
|
|
60
|
-
end
|
|
73
|
+
expected_raw = row.fetch("hf_raw_token_ids")
|
|
74
|
+
got_raw = model.tokenize(text)
|
|
75
|
+
if got_raw != expected_raw
|
|
76
|
+
raw_failures << i
|
|
77
|
+
first = got_raw.zip(expected_raw).index { |a, b| a != b } || [got_raw.length, expected_raw.length].min
|
|
78
|
+
problems << "raw ids differ at #{first} (got #{got_raw.length}, ref #{expected_raw.length})"
|
|
61
79
|
end
|
|
62
80
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
0.0
|
|
72
|
-
else
|
|
73
|
-
dot(ref, got) / (norm(ref) * norm(got))
|
|
74
|
-
end
|
|
81
|
+
full_raw = model.tokenize(text, max_tokens: false)
|
|
82
|
+
expected_usable = row.fetch("static_usable_token_ids")
|
|
83
|
+
got_usable = full_raw.reject { |id| id == model.unk_id }.first(max_length)
|
|
84
|
+
if got_usable != expected_usable
|
|
85
|
+
usable_failures << i
|
|
86
|
+
first = got_usable.zip(expected_usable).index { |a, b| a != b } || [got_usable.length, expected_usable.length].min
|
|
87
|
+
problems << "usable ids differ at #{first} (got #{got_usable.length}, ref #{expected_usable.length})"
|
|
88
|
+
end
|
|
75
89
|
|
|
76
|
-
|
|
77
|
-
|
|
90
|
+
got_vector_blob = model.embed(text)
|
|
91
|
+
pooled_blob = model.embed_token_ids(full_raw)
|
|
92
|
+
unless got_vector_blob == pooled_blob
|
|
93
|
+
invariant_failures << i
|
|
94
|
+
problems << "embed(text) != embed_token_ids(unbounded tokenize(text))"
|
|
95
|
+
end
|
|
78
96
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
97
|
+
model2vec_ids = row.fetch("model2vec_token_ids")
|
|
98
|
+
declared_deviation = row.fetch("model2vec_character_pretruncate_changes_ids")
|
|
99
|
+
actual_deviation = model2vec_ids != expected_usable
|
|
100
|
+
if actual_deviation != declared_deviation
|
|
101
|
+
problems << "oracle character-pretruncate flag is inconsistent"
|
|
102
|
+
usable_failures << i unless usable_failures.include?(i)
|
|
103
|
+
elsif actual_deviation
|
|
104
|
+
intentional_deviations << i
|
|
105
|
+
else
|
|
106
|
+
reference_vector = row.fetch("model2vec_vector")
|
|
107
|
+
got_vector = got_vector_blob.unpack("e*")
|
|
108
|
+
cosine, max_abs = vector_metrics(reference_vector, got_vector)
|
|
109
|
+
vectors_checked += 1
|
|
110
|
+
min_cosine = [min_cosine, cosine].min
|
|
111
|
+
max_abs_all = [max_abs_all, max_abs].max
|
|
112
|
+
unless cosine >= options[:min_cosine] && max_abs <= options[:max_abs]
|
|
113
|
+
vector_failures << i
|
|
114
|
+
problems << format("vector out of tolerance cos=%.10f max_abs=%.8g", cosine, max_abs)
|
|
115
|
+
end
|
|
82
116
|
end
|
|
83
117
|
|
|
84
118
|
status = problems.empty? ? "ok" : "FAIL"
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
line += " [#{problems.join('; ')}]" unless problems.empty?
|
|
89
|
-
puts line
|
|
119
|
+
suffix = actual_deviation ? " intentional-character-pretruncate-deviation" : ""
|
|
120
|
+
puts "#{status} idx=#{format('%03d', i)} label=#{label.inspect} bytes=#{text.bytesize}#{suffix}" +
|
|
121
|
+
(problems.empty? ? "" : " [#{problems.join('; ')}]")
|
|
90
122
|
end
|
|
91
123
|
|
|
92
124
|
puts "rows=#{rows.length}"
|
|
93
|
-
puts "
|
|
94
|
-
puts "
|
|
95
|
-
puts "
|
|
96
|
-
puts "
|
|
125
|
+
puts "vectors_checked=#{vectors_checked}"
|
|
126
|
+
puts "intentional_character_pretruncate_deviations=#{intentional_deviations.length}"
|
|
127
|
+
puts "min_cosine=#{min_cosine}" if vectors_checked.positive?
|
|
128
|
+
puts "max_abs_all=#{max_abs_all}" if vectors_checked.positive?
|
|
129
|
+
puts "raw_token_id_failures=#{raw_failures.inspect}"
|
|
130
|
+
puts "usable_token_id_failures=#{usable_failures.inspect}"
|
|
131
|
+
puts "embed_invariant_failures=#{invariant_failures.inspect}"
|
|
97
132
|
puts "vector_failures=#{vector_failures.inspect}"
|
|
98
133
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
end
|
|
102
|
-
|
|
103
|
-
unless id_failures.empty? && vector_failures.empty?
|
|
104
|
-
abort "parity failed: token ids #{id_failures.inspect}, vectors #{vector_failures.inspect}"
|
|
134
|
+
unless raw_failures.empty? && usable_failures.empty? && invariant_failures.empty? && vector_failures.empty?
|
|
135
|
+
abort "parity failed"
|
|
105
136
|
end
|
|
106
137
|
|
|
107
|
-
puts "parity OK"
|
|
138
|
+
puts "corpus parity OK (#{rows.length}/#{rows.length}); intentional Model2Vec character pre-truncation deviations are reported separately"
|