NetworkIsLife commited on
Commit
9341b94
·
verified ·
1 Parent(s): a2e3ab2

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +178 -79
README.md CHANGED
@@ -13,126 +13,225 @@ This is a [sentence-transformers](https://www.SBERT.net) model: It maps sentence
13
 
14
  <!--- Describe your model here -->
15
 
16
- ## Usage (Sentence-Transformers)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- Using this model becomes easy when you have [sentence-transformers](https://www.SBERT.net) installed:
19
 
20
- ```
21
- pip install -U sentence-transformers
22
- ```
23
 
24
- Then you can use the model like this:
25
 
26
- ```python
27
- from sentence_transformers import SentenceTransformer
28
- sentences = ["This is an example sentence", "Each sentence is converted"]
29
 
30
- model = SentenceTransformer('pritamdeka/S-Scibert-snli-multinli-stsb')
31
- embeddings = model.encode(sentences)
32
- print(embeddings)
33
- ```
34
 
 
35
 
 
36
 
37
- ## Usage (HuggingFace Transformers)
38
- Without [sentence-transformers](https://www.SBERT.net), you can use the model like this: First, you pass your input through the transformer model, then you have to apply the right pooling-operation on-top of the contextualized word embeddings.
39
 
40
- ```python
41
- from transformers import AutoTokenizer, AutoModel
42
- import torch
43
 
 
44
 
45
- #Mean Pooling - Take attention mask into account for correct averaging
46
- def mean_pooling(model_output, attention_mask):
47
- token_embeddings = model_output[0] #First element of model_output contains all token embeddings
48
- input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
49
- return torch.sum(token_embeddings * input_mask_expanded, 1) / torch.clamp(input_mask_expanded.sum(1), min=1e-9)
50
 
 
51
 
52
- # Sentences we want sentence embeddings for
53
- sentences = ['This is an example sentence', 'Each sentence is converted']
 
 
 
 
 
 
 
 
 
 
54
 
55
- # Load model from HuggingFace Hub
56
- tokenizer = AutoTokenizer.from_pretrained('pritamdeka/S-Scibert-snli-multinli-stsb')
57
- model = AutoModel.from_pretrained('pritamdeka/S-Scibert-snli-multinli-stsb')
58
 
59
- # Tokenize sentences
60
- encoded_input = tokenizer(sentences, padding=True, truncation=True, return_tensors='pt')
 
 
61
 
62
- # Compute token embeddings
63
- with torch.no_grad():
64
- model_output = model(**encoded_input)
 
 
 
65
 
66
- # Perform pooling. In this case, max pooling.
67
- sentence_embeddings = mean_pooling(model_output, encoded_input['attention_mask'])
68
 
69
- print("Sentence embeddings:")
70
- print(sentence_embeddings)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
  ```
72
 
 
73
 
 
 
 
 
 
 
 
74
 
75
- ## Evaluation Results
76
 
77
- <!--- Describe how your model was evaluated -->
 
 
 
 
 
 
 
 
 
78
 
79
- For an automated evaluation of this model, see the *Sentence Embeddings Benchmark*: [https://seb.sbert.net](https://seb.sbert.net?model_name={MODEL_NAME})
80
 
 
81
 
82
- ## Training
83
- The model was trained with the parameters:
84
 
85
- **DataLoader**:
 
 
 
 
 
 
 
86
 
87
- `torch.utils.data.dataloader.DataLoader` of length 90 with parameters:
88
- ```
89
- {'batch_size': 64, 'sampler': 'torch.utils.data.sampler.RandomSampler', 'batch_sampler': 'torch.utils.data.sampler.BatchSampler'}
 
 
 
 
 
 
 
 
 
 
 
90
  ```
91
 
92
- **Loss**:
93
 
94
- `sentence_transformers.losses.CosineSimilarityLoss.CosineSimilarityLoss`
 
 
 
 
 
 
 
95
 
96
- Parameters of the fit()-Method:
97
- ```
98
- {
99
- "callback": null,
100
- "epochs": 4,
101
- "evaluation_steps": 1000,
102
- "evaluator": "sentence_transformers.evaluation.EmbeddingSimilarityEvaluator.EmbeddingSimilarityEvaluator",
103
- "max_grad_norm": 1,
104
- "optimizer_class": "<class 'transformers.optimization.AdamW'>",
105
- "optimizer_params": {
106
- "lr": 2e-05
107
- },
108
- "scheduler": "WarmupLinear",
109
- "steps_per_epoch": null,
110
- "warmup_steps": 36,
111
- "weight_decay": 0.01
112
- }
113
- ```
114
 
 
115
 
116
- ## Full Model Architecture
117
- ```
118
- SentenceTransformer(
119
- (0): Transformer({'max_seq_length': 75, 'do_lower_case': False}) with Transformer model: BertModel
120
- (1): Pooling({'word_embedding_dimension': 768, 'pooling_mode_cls_token': False, 'pooling_mode_mean_tokens': True, 'pooling_mode_max_tokens': False, 'pooling_mode_mean_sqrt_len_tokens': False})
121
- )
 
 
 
 
 
 
 
122
  ```
123
 
124
- ## Citing & Authors
125
 
126
- <!--- Describe where people can find more information -->
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
- If you use the model kindly cite the following work
129
 
130
- ```
 
 
131
  @inproceedings{deka2021unsupervised,
132
- title={Unsupervised Keyword Combination Query Generation from Online Health Related Content for Evidence-Based Fact Checking},
 
133
  author={Deka, Pritam and Jurek-Loughrey, Anna},
134
- booktitle={The 23rd International Conference on Information Integration and Web Intelligence},
 
135
  pages={267--277},
136
  year={2021}
137
  }
138
- ```
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
 
14
  <!--- Describe your model here -->
15
 
16
+ ---
17
+ license: apache-2.0
18
+ language:
19
+ - en
20
+ library_name: sentence-transformers
21
+ tags:
22
+ - bert
23
+ - scibert
24
+ - sentence-transformers
25
+ - sentence-similarity
26
+ - scientific-text
27
+ - mirror
28
+ - r-compatible
29
+ base_model: pritamdeka/S-Scibert-snli-multinli-stsb
30
+ pipeline_tag: sentence-similarity
31
+ ---
32
 
33
+ # S-SciBERT (snli-multinli-stsb) — safetensors mirror for use from R
34
 
35
+ This is a format-converted mirror of [`pritamdeka/S-Scibert-snli-multinli-stsb`](https://huggingface.co/pritamdeka/S-Scibert-snli-multinli-stsb), maintained for teaching a course on transformer-based topic modeling in R.
 
 
36
 
37
+ The model itself is unchanged: same architecture, same weights, same tokenizer, same outputs as the upstream original. What's different is the on-disk format and provenance, both of which matter for a teaching context.
38
 
39
+ ## Why this mirror exists
 
 
40
 
41
+ The upstream repo ships `pytorch_model.bin` (PyTorch pickle format) and no `tokenizer.json`. For Python users this works fine, but for R users working through the `torch` (libtorch) and `safetensors` R packages there is a more serious problem than just format inconvenience:
 
 
 
42
 
43
+ **The upstream pickle file was saved while the model was on a CUDA device.** PyTorch's pickle format records the device of every tensor, so loading on a CPU-only machine fails with an `aten::empty_strided ... CUDA backend` error. Python's `torch.load(map_location='cpu')` rescues you from this, but R-torch's loader doesn't expose that argument, so the upstream file is effectively unusable from R unless you have a CUDA GPU available.
44
 
45
+ This mirror adds:
46
 
47
+ - `model.safetensors` — the same weights in [safetensors](https://huggingface.co/docs/safetensors) format. Safetensors files do not record device information at all, so they load cleanly regardless of where the model was originally saved or what hardware the user has.
 
48
 
49
+ The fix is structural, not just cosmetic: safetensors solves a class of cross-device portability problems that pickle cannot, on top of being safer and faster to read.
 
 
50
 
51
+ ## What it is, briefly
52
 
53
+ S-SciBERT is [SciBERT-cased](https://huggingface.co/allenai/scibert_scivocab_cased) fine-tuned for sentence similarity using the [sentence-transformers](https://www.sbert.net) framework. The fine-tuning data was the standard general-English similarity benchmark suite: SNLI (natural language inference), MultiNLI (multi-genre NLI), and STS-B (semantic textual similarity).
 
 
 
 
54
 
55
+ The result is a model that combines SciBERT's scientific vocabulary (gene names, chemical terms, ML jargon) with sentence-transformer-quality embeddings — meaning the mean-pooled output vectors actually cluster well, which base SciBERT's do not.
56
 
57
+ | Property | Value |
58
+ |----------|-------|
59
+ | Architecture | BERT-base + mean-pooling head |
60
+ | Parameters | ~110M |
61
+ | Embedding dimension | 768 |
62
+ | Layers | 12 |
63
+ | Attention heads | 12 |
64
+ | Vocabulary | SciBERT scientific (cased, ~31K tokens) |
65
+ | Pooling | Mean over tokens (masked by attention) |
66
+ | Fine-tuning data | SNLI + MultiNLI + STS-B |
67
+ | Training max_seq_length | 75 tokens |
68
+ | Case sensitivity | Cased |
69
 
70
+ ## When to use this model
 
 
71
 
72
+ **Good fit:**
73
+ - Topic modeling, clustering, or semantic search over scientific text (papers, abstracts, scientific tweets, GitHub issues from research codebases).
74
+ - Domains where SciBERT's vocabulary is an advantage: biomedical, computer science, computational biology, machine learning, chemistry.
75
+ - Sentence-level or paragraph-level inputs.
76
 
77
+ **Less good fit:**
78
+ - General web text — a general-purpose sentence-transformer like `all-MiniLM-L6-v2` or `all-mpnet-base-v2` will likely match or beat S-SciBERT on non-scientific content.
79
+ - Document-level inputs (full papers): the model was fine-tuned on sequences of 75 tokens. It still runs on longer inputs (up to the BERT-base ceiling of 512), but quality degrades for content past the trained length. For long documents, split into sentences or paragraphs and embed those individually.
80
+ - Languages other than English: the fine-tuning data is English-only.
81
+
82
+ ## Usage from R
83
 
84
+ This mirror works with a pure-R BERT inference pipeline built on top of the `torch` (libtorch) R package, with no Python at runtime:
 
85
 
86
+ ```r
87
+ source("bert_r.R")
88
+ enc <- load_hf_bert("NetworkIsLife/S-SciBert_DAFS")
89
+
90
+ emb <- embed_texts(enc$model, enc$tokenizer,
91
+ c("CRISPR-Cas9 enables targeted gene editing.",
92
+ "Glioblastoma exhibits invasive growth patterns.",
93
+ "Gradient descent minimizes a loss function."),
94
+ max_length = 128)
95
+ dim(emb) # 3 x 768
96
+
97
+ # Cosine similarity (embeddings are L2-normalized by default)
98
+ sims <- emb %*% t(emb)
99
+ round(sims, 3)
100
+ # Rows 1 and 2 should be more similar to each other (both biomedical)
101
+ # than either is to row 3 (machine learning)
102
  ```
103
 
104
+ For topic modeling with the full pipeline:
105
 
106
+ ```r
107
+ source("bertopic_r.R")
108
+ fit <- fit_bertopic(enc, docs = my_abstracts,
109
+ umap_n_neighbors = 15,
110
+ hdbscan_min_pts = 10)
111
+ print_topics(fit)
112
+ ```
113
 
114
+ For long-term reproducibility in course materials, pin to a specific revision:
115
 
116
+ ```r
117
+ enc <- load_hf_bert(
118
+ "NetworkIsLife/S-SciBert_DAFS",
119
+ weights_path = hfhub::hub_download(
120
+ "NetworkIsLife/S-SciBert_DAFS",
121
+ "model.safetensors",
122
+ revision = "MAIN_COMMIT_HASH_HERE"
123
+ )
124
+ )
125
+ ```
126
 
127
+ Replace `MAIN_COMMIT_HASH_HERE` with the commit hash visible in this repo's commit history.
128
 
129
+ ## Usage from Python
130
 
131
+ Either of the standard idioms works:
 
132
 
133
+ ```python
134
+ # Via sentence-transformers (easiest)
135
+ from sentence_transformers import SentenceTransformer
136
+ model = SentenceTransformer("NetworkIsLife/S-SciBert_DAFS")
137
+ embeddings = model.encode([
138
+ "CRISPR-Cas9 enables targeted gene editing.",
139
+ "Glioblastoma exhibits invasive growth patterns."
140
+ ])
141
 
142
+ # Via transformers (with manual mean pooling)
143
+ from transformers import AutoTokenizer, AutoModel
144
+ import torch
145
+ import torch.nn.functional as F
146
+
147
+ tok = AutoTokenizer.from_pretrained("NetworkIsLife/S-SciBert_DAFS")
148
+ mod = AutoModel.from_pretrained("NetworkIsLife/S-SciBert_DAFS").eval()
149
+
150
+ enc = tok(sentences, padding=True, truncation=True, return_tensors="pt", max_length=128)
151
+ with torch.no_grad():
152
+ out = mod(**enc).last_hidden_state
153
+ m = enc["attention_mask"].unsqueeze(-1).float()
154
+ pooled = (out * m).sum(1) / m.sum(1).clamp(min=1e-9)
155
+ embeddings = F.normalize(pooled, p=2, dim=1)
156
  ```
157
 
158
+ ## Files in this repo
159
 
160
+ | File | Source | Purpose |
161
+ |------|--------|---------|
162
+ | `model.safetensors` | converted from upstream `pytorch_model.bin` | model weights, modern format (device-agnostic) |
163
+ | `pytorch_model.bin` | copied from upstream | model weights, legacy format (kept for compatibility) |
164
+ | `config.json` | copied from upstream | BERT architecture parameters |
165
+ | `vocab.txt` | copied from upstream | SciBERT WordPiece vocabulary |
166
+ | `tokenizer_config.json` | copied from upstream (if present) | tokenizer settings (do_lower_case, special tokens) |
167
+ | `README.md` | this file | provenance and usage |
168
 
169
+ ## Provenance and verification
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
 
171
+ The `model.safetensors` file in this repo was produced by HuggingFace's official `SFconvertbot` (the same automated conversion used across thousands of HuggingFace repos). The conversion is purely a re-serialization — every tensor in the safetensors file is bit-identical to the corresponding tensor in `pytorch_model.bin`. No re-training, no quantization, no precision loss.
172
 
173
+ You can verify this yourself in Python:
174
+
175
+ ```python
176
+ import torch
177
+ from safetensors.torch import load_file
178
+
179
+ # map_location='cpu' is needed because the upstream pickle was saved on GPU
180
+ a = torch.load("pytorch_model.bin", map_location="cpu", weights_only=True)
181
+ b = load_file("model.safetensors")
182
+ assert set(a.keys()) == set(b.keys())
183
+ for k in a:
184
+ assert torch.equal(a[k].cpu(), b[k]), f"Mismatch in {k}"
185
+ print("Bit-identical.")
186
  ```
187
 
188
+ End-to-end verification (cosine similarities computed via the upstream model and via this mirror should agree to ~1e-6):
189
 
190
+ ```python
191
+ from sentence_transformers import SentenceTransformer
192
+ import numpy as np
193
+
194
+ sentences = [
195
+ "CRISPR-Cas9 enables targeted gene editing.",
196
+ "Glioblastoma exhibits invasive growth.",
197
+ "Gradient descent minimizes a loss function."
198
+ ]
199
+ a = SentenceTransformer("pritamdeka/S-Scibert-snli-multinli-stsb").encode(sentences)
200
+ b = SentenceTransformer("NetworkIsLife/S-SciBert_DAFS").encode(sentences)
201
+ print("max |Δ| =", np.abs(a - b).max()) # should be ~1e-6 or smaller
202
+ ```
203
 
204
+ ## License and citation
205
 
206
+ This mirror inherits the upstream license: **Apache 2.0**. If you use this model in academic work, please cite the original paper:
207
+
208
+ ```bibtex
209
  @inproceedings{deka2021unsupervised,
210
+ title={Unsupervised Keyword Combination Query Generation from
211
+ Online Health Related Content for Evidence-Based Fact Checking},
212
  author={Deka, Pritam and Jurek-Loughrey, Anna},
213
+ booktitle={The 23rd International Conference on Information Integration
214
+ and Web-based Applications & Services},
215
  pages={267--277},
216
  year={2021}
217
  }
218
+ ```
219
+
220
+ And consider also citing the underlying SciBERT paper that this model fine-tunes from:
221
+
222
+ ```bibtex
223
+ @inproceedings{beltagy-etal-2019-scibert,
224
+ title = "{SciBERT}: A Pretrained Language Model for Scientific Text",
225
+ author = "Beltagy, Iz and Lo, Kyle and Cohan, Arman",
226
+ booktitle = "Proceedings of EMNLP-IJCNLP",
227
+ year = "2019",
228
+ url = "https://www.aclweb.org/anthology/D19-1371"
229
+ }
230
+ ```
231
+
232
+ Original model: [`pritamdeka/S-Scibert-snli-multinli-stsb`](https://huggingface.co/pritamdeka/S-Scibert-snli-multinli-stsb) by Pritam Deka.
233
+ Base model: [`allenai/scibert_scivocab_cased`](https://huggingface.co/allenai/scibert_scivocab_cased) by the Allen Institute for AI.
234
+
235
+ ## Maintenance
236
+
237
+ This is a teaching artifact for a course on transformer-based topic modeling in R. It will not be updated except to fix conversion errors. For the canonical, maintained version of S-SciBERT, see the [upstream repo](https://huggingface.co/pritamdeka/S-Scibert-snli-multinli-stsb).