Instructions to use Taykhoom/ERNIE-RNA with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use Taykhoom/ERNIE-RNA with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("fill-mask", model="Taykhoom/ERNIE-RNA", trust_remote_code=True)# pip install -U transformers accelerate # Load model directly from transformers import AutoModelForMaskedLM model = AutoModelForMaskedLM.from_pretrained("Taykhoom/ERNIE-RNA", trust_remote_code=True, device_map="auto") - Notebooks
- Google Colab
- Kaggle
Commit ·
d6ace23
0
Parent(s):
Initial ERNIE-RNA Hugging Face port
Browse files- .gitattributes +35 -0
- README.md +154 -0
- config.json +26 -0
- configuration_ernierna.py +45 -0
- modeling_ernierna.py +322 -0
- pytorch_model.bin +3 -0
- special_tokens_map.json +7 -0
- tokenization_ernierna.py +115 -0
- tokenizer_config.json +56 -0
- vocab.json +27 -0
.gitattributes
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
*.7z filter=lfs diff=lfs merge=lfs -text
|
| 2 |
+
*.arrow filter=lfs diff=lfs merge=lfs -text
|
| 3 |
+
*.bin filter=lfs diff=lfs merge=lfs -text
|
| 4 |
+
*.bz2 filter=lfs diff=lfs merge=lfs -text
|
| 5 |
+
*.ckpt filter=lfs diff=lfs merge=lfs -text
|
| 6 |
+
*.ftz filter=lfs diff=lfs merge=lfs -text
|
| 7 |
+
*.gz filter=lfs diff=lfs merge=lfs -text
|
| 8 |
+
*.h5 filter=lfs diff=lfs merge=lfs -text
|
| 9 |
+
*.joblib filter=lfs diff=lfs merge=lfs -text
|
| 10 |
+
*.lfs.* filter=lfs diff=lfs merge=lfs -text
|
| 11 |
+
*.mlmodel filter=lfs diff=lfs merge=lfs -text
|
| 12 |
+
*.model filter=lfs diff=lfs merge=lfs -text
|
| 13 |
+
*.msgpack filter=lfs diff=lfs merge=lfs -text
|
| 14 |
+
*.npy filter=lfs diff=lfs merge=lfs -text
|
| 15 |
+
*.npz filter=lfs diff=lfs merge=lfs -text
|
| 16 |
+
*.onnx filter=lfs diff=lfs merge=lfs -text
|
| 17 |
+
*.ot filter=lfs diff=lfs merge=lfs -text
|
| 18 |
+
*.parquet filter=lfs diff=lfs merge=lfs -text
|
| 19 |
+
*.pb filter=lfs diff=lfs merge=lfs -text
|
| 20 |
+
*.pickle filter=lfs diff=lfs merge=lfs -text
|
| 21 |
+
*.pkl filter=lfs diff=lfs merge=lfs -text
|
| 22 |
+
*.pt filter=lfs diff=lfs merge=lfs -text
|
| 23 |
+
*.pth filter=lfs diff=lfs merge=lfs -text
|
| 24 |
+
*.rar filter=lfs diff=lfs merge=lfs -text
|
| 25 |
+
*.safetensors filter=lfs diff=lfs merge=lfs -text
|
| 26 |
+
saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
| 27 |
+
*.tar.* filter=lfs diff=lfs merge=lfs -text
|
| 28 |
+
*.tar filter=lfs diff=lfs merge=lfs -text
|
| 29 |
+
*.tflite filter=lfs diff=lfs merge=lfs -text
|
| 30 |
+
*.tgz filter=lfs diff=lfs merge=lfs -text
|
| 31 |
+
*.wasm filter=lfs diff=lfs merge=lfs -text
|
| 32 |
+
*.xz filter=lfs diff=lfs merge=lfs -text
|
| 33 |
+
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
+
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
+
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
library_name: transformers
|
| 3 |
+
tags:
|
| 4 |
+
- RNA
|
| 5 |
+
- language-model
|
| 6 |
+
license: mit
|
| 7 |
+
---
|
| 8 |
+
|
| 9 |
+
# ERNIE-RNA
|
| 10 |
+
|
| 11 |
+
ERNIE-RNA is an RNA-specific large language model that incorporates RNA base-pairing potential as a recurrent 2D structural bias into each attention layer, enabling the model to capture secondary structure information during pretraining.
|
| 12 |
+
|
| 13 |
+
## Architecture
|
| 14 |
+
|
| 15 |
+
| Parameter | Value |
|
| 16 |
+
|---|---|
|
| 17 |
+
| Layers | 12 |
|
| 18 |
+
| Attention heads | 12 |
|
| 19 |
+
| Embedding dimension | 768 |
|
| 20 |
+
| FFN hidden dimension | 3072 (GELU) |
|
| 21 |
+
| Vocabulary size | 25 |
|
| 22 |
+
| Positional encoding | Sinusoidal (fairseq-style) |
|
| 23 |
+
| Normalization | LayerNorm (embedding and post-residual) |
|
| 24 |
+
| Architecture | Post-LN Transformer with recurrent 2D RNA pairing bias |
|
| 25 |
+
| Max sequence length | 1024 |
|
| 26 |
+
|
| 27 |
+
### Vocabulary
|
| 28 |
+
|
| 29 |
+
| Token | ID | Notes |
|
| 30 |
+
|---|---|---|
|
| 31 |
+
| `<cls>` | 0 | Prepended to every sequence |
|
| 32 |
+
| `<pad>` | 1 | Padding token |
|
| 33 |
+
| `<eos>` | 2 | Appended to every sequence |
|
| 34 |
+
| `<unk>` | 3 | Unknown token |
|
| 35 |
+
| G | 4 | |
|
| 36 |
+
| A | 5 | |
|
| 37 |
+
| U | 6 | T is silently mapped to U during tokenization |
|
| 38 |
+
| C | 7 | |
|
| 39 |
+
| N | 8 | Ambiguous nucleotide |
|
| 40 |
+
| Y, R, S, K, W, M, D, H, V, B | 9-18 | IUPAC ambiguity codes |
|
| 41 |
+
| X | 19 | Unknown/ambiguous nucleotide |
|
| 42 |
+
| I | 20 | Inosine |
|
| 43 |
+
| madeupword0000-madeupword0002 | 21-23 | Placeholder tokens from the original fairseq vocabulary |
|
| 44 |
+
| `<mask>` | 24 | MLM mask token |
|
| 45 |
+
|
| 46 |
+
### 2D RNA Pairing Bias
|
| 47 |
+
|
| 48 |
+
ERNIE-RNA computes a pairwise RNA base-pairing potential matrix from the input sequence at the start of each forward pass. This matrix (shape `[B, T, T, 1]`) is projected to `[B, H, T, T]` via a 2-layer MLP (1 -> 6 -> H, with GELU) and added to the attention logits in the first layer. The pre-softmax attention scores then become the updated 2D bias for the next layer, creating a recurrent structural information pathway across all 12 transformer layers.
|
| 49 |
+
|
| 50 |
+
Base-pairing scores: A-U = 2.0, G-C = 3.0, G-U wobble = 0.8.
|
| 51 |
+
|
| 52 |
+
## Pretraining
|
| 53 |
+
|
| 54 |
+
- **Objective:** Masked language modeling (MLM) on RNA sequences
|
| 55 |
+
- **Data:** RNAcentral (non-redundant RNA sequences)
|
| 56 |
+
- **Source checkpoint:** `ERNIE-RNA_pretrain.pt`
|
| 57 |
+
|
| 58 |
+
### Checkpoint selection
|
| 59 |
+
|
| 60 |
+
Single pretrained checkpoint from the original repository. Used as-is; no fine-tuned variants are included in this release.
|
| 61 |
+
|
| 62 |
+
## Parity Verification
|
| 63 |
+
|
| 64 |
+
Hidden-state representations verified identical (max abs diff = 1.82e-06) to the original
|
| 65 |
+
implementation at all 13 representation levels (embedding + 12 transformer layers).
|
| 66 |
+
Verified on GPU with PyTorch 2.7 / CUDA 12.
|
| 67 |
+
|
| 68 |
+
Only `attn_implementation="eager"` is supported (see Implementation Notes).
|
| 69 |
+
|
| 70 |
+
## Related Models
|
| 71 |
+
|
| 72 |
+
See the full [ERNIE-RNA collection](https://huggingface.co/collections/Taykhoom/ernie-rna-6a20c1a8ea56c00a74e2dd93).
|
| 73 |
+
|
| 74 |
+
| Model | Notes |
|
| 75 |
+
|---|---|
|
| 76 |
+
| **[Taykhoom/ERNIE-RNA](https://huggingface.co/Taykhoom/ERNIE-RNA)** | **Pretrained model (this model)** |
|
| 77 |
+
| [Taykhoom/ERNIE-RNA-SS](https://huggingface.co/Taykhoom/ERNIE-RNA-SS) | SS fine-tuned (RNA3DB), backbone only |
|
| 78 |
+
| [Taykhoom/ERNIE-RNA-MRL](https://huggingface.co/Taykhoom/ERNIE-RNA-MRL) | UTR MRL fine-tuned, backbone only |
|
| 79 |
+
|
| 80 |
+
## Usage
|
| 81 |
+
|
| 82 |
+
### Embedding generation
|
| 83 |
+
|
| 84 |
+
```python
|
| 85 |
+
import torch
|
| 86 |
+
from transformers import AutoTokenizer, AutoModel
|
| 87 |
+
|
| 88 |
+
tokenizer = AutoTokenizer.from_pretrained("Taykhoom/ERNIE-RNA", trust_remote_code=True)
|
| 89 |
+
model = AutoModel.from_pretrained("Taykhoom/ERNIE-RNA", trust_remote_code=True)
|
| 90 |
+
model.eval()
|
| 91 |
+
|
| 92 |
+
sequences = ["AUGCAUGCAUGC", "GGGGCCCCGGGG"]
|
| 93 |
+
enc = tokenizer(sequences, return_tensors="pt", padding=True)
|
| 94 |
+
|
| 95 |
+
with torch.no_grad():
|
| 96 |
+
out = model(**enc)
|
| 97 |
+
|
| 98 |
+
cls_emb = out.last_hidden_state[:, 0, :] # (batch, 768) -- CLS token
|
| 99 |
+
token_emb = out.last_hidden_state # (batch, seq_len, 768)
|
| 100 |
+
|
| 101 |
+
# Intermediate layers
|
| 102 |
+
out_all = model(**enc, output_hidden_states=True)
|
| 103 |
+
layer6_emb = out_all.hidden_states[6] # (batch, seq_len, 768)
|
| 104 |
+
```
|
| 105 |
+
|
| 106 |
+
### MLM logits
|
| 107 |
+
|
| 108 |
+
```python
|
| 109 |
+
import torch
|
| 110 |
+
from transformers import AutoTokenizer, AutoModelForMaskedLM
|
| 111 |
+
|
| 112 |
+
tokenizer = AutoTokenizer.from_pretrained("Taykhoom/ERNIE-RNA", trust_remote_code=True)
|
| 113 |
+
model = AutoModelForMaskedLM.from_pretrained("Taykhoom/ERNIE-RNA", trust_remote_code=True)
|
| 114 |
+
model.eval()
|
| 115 |
+
|
| 116 |
+
enc = tokenizer(["AUG<mask>AUG"], return_tensors="pt")
|
| 117 |
+
with torch.no_grad():
|
| 118 |
+
logits = model(**enc).logits # (1, seq_len, 25)
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
### Fine-tuning
|
| 122 |
+
|
| 123 |
+
Use the CLS token embedding (`last_hidden_state[:, 0, :]`) as input to a prediction head for sequence-level tasks. For token-level tasks, use `last_hidden_state` directly.
|
| 124 |
+
|
| 125 |
+
## Implementation Notes
|
| 126 |
+
|
| 127 |
+
ERNIE-RNA's recurrent 2D bias is updated from the pre-softmax attention scores at every layer (the raw QK logits become the bias input for the next layer). Fused attention kernels (SDPA, FlashAttention) do not expose pre-softmax scores, so they cannot maintain this recurrent pathway. Only `attn_implementation="eager"` is supported; requesting `sdpa` or `flash_attention_2` raises a `ValueError`.
|
| 128 |
+
|
| 129 |
+
The `twod_proj` MLP is always run in float32 (matching the original) regardless of the model's compute dtype.
|
| 130 |
+
|
| 131 |
+
## Citation
|
| 132 |
+
|
| 133 |
+
```bibtex
|
| 134 |
+
@article{yin2025_ernierna,
|
| 135 |
+
title = {{ERNIE-RNA}: an {RNA} language model with structure-enhanced representations},
|
| 136 |
+
author = {Yin, Weijie and Zhang, Zhaoyu and Zhang, Shuo and He, Liang and Zhang, Ruiyang and Jiang, Rui and Liu, Gan and Wang, Jingyi and Zhang, Xuegong and Qin, Tao and Xie, Zhen},
|
| 137 |
+
journal = {Nature Communications},
|
| 138 |
+
volume = {16},
|
| 139 |
+
number = {1},
|
| 140 |
+
pages = {8407},
|
| 141 |
+
year = {2025},
|
| 142 |
+
doi = {10.1038/s41467-025-64972-0}
|
| 143 |
+
}
|
| 144 |
+
```
|
| 145 |
+
|
| 146 |
+
## Credits
|
| 147 |
+
|
| 148 |
+
Original model and code by Yin et al. Source: [GitHub](https://github.com/Bruce-ywj/ERNIE-RNA).
|
| 149 |
+
The HF conversion code was authored primarily by [Claude Code](https://claude.ai/code)
|
| 150 |
+
and reviewed manually by Taykhoom Dalal.
|
| 151 |
+
|
| 152 |
+
## License
|
| 153 |
+
|
| 154 |
+
MIT, following the original repository.
|
config.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"activation_dropout": 0.0,
|
| 3 |
+
"activation_fn": "gelu",
|
| 4 |
+
"architectures": [
|
| 5 |
+
"ErnieRNAForMaskedLM"
|
| 6 |
+
],
|
| 7 |
+
"attention_dropout": 0.1,
|
| 8 |
+
"attention_heads": 12,
|
| 9 |
+
"auto_map": {
|
| 10 |
+
"AutoConfig": "configuration_ernierna.ErnieRNAConfig",
|
| 11 |
+
"AutoModel": "modeling_ernierna.ErnieRNAModel",
|
| 12 |
+
"AutoModelForMaskedLM": "modeling_ernierna.ErnieRNAForMaskedLM"
|
| 13 |
+
},
|
| 14 |
+
"dropout": 0.1,
|
| 15 |
+
"embed_dim": 768,
|
| 16 |
+
"ffn_embed_dim": 3072,
|
| 17 |
+
"mask_idx": 24,
|
| 18 |
+
"max_positions": 1024,
|
| 19 |
+
"model_max_length": 1024,
|
| 20 |
+
"model_type": "ernie_rna",
|
| 21 |
+
"num_layers": 12,
|
| 22 |
+
"num_segments": 2,
|
| 23 |
+
"padding_idx": 1,
|
| 24 |
+
"transformers_version": "4.57.6",
|
| 25 |
+
"vocab_size": 25
|
| 26 |
+
}
|
configuration_ernierna.py
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from transformers import PretrainedConfig
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class ErnieRNAConfig(PretrainedConfig):
|
| 5 |
+
model_type = "ernie_rna"
|
| 6 |
+
|
| 7 |
+
auto_map = {
|
| 8 |
+
"AutoConfig": "configuration_ernierna.ErnieRNAConfig",
|
| 9 |
+
"AutoModel": "modeling_ernierna.ErnieRNAModel",
|
| 10 |
+
"AutoModelForMaskedLM": "modeling_ernierna.ErnieRNAForMaskedLM",
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
def __init__(
|
| 14 |
+
self,
|
| 15 |
+
vocab_size=25,
|
| 16 |
+
num_layers=12,
|
| 17 |
+
embed_dim=768,
|
| 18 |
+
ffn_embed_dim=3072,
|
| 19 |
+
attention_heads=12,
|
| 20 |
+
dropout=0.1,
|
| 21 |
+
attention_dropout=0.1,
|
| 22 |
+
activation_dropout=0.0,
|
| 23 |
+
activation_fn="gelu",
|
| 24 |
+
max_positions=1024,
|
| 25 |
+
padding_idx=1,
|
| 26 |
+
mask_idx=24,
|
| 27 |
+
num_segments=2,
|
| 28 |
+
model_max_length=1024,
|
| 29 |
+
**kwargs,
|
| 30 |
+
):
|
| 31 |
+
super().__init__(padding_idx=padding_idx, **kwargs)
|
| 32 |
+
self.auto_map = dict(type(self).auto_map)
|
| 33 |
+
self.vocab_size = vocab_size
|
| 34 |
+
self.num_layers = num_layers
|
| 35 |
+
self.embed_dim = embed_dim
|
| 36 |
+
self.ffn_embed_dim = ffn_embed_dim
|
| 37 |
+
self.attention_heads = attention_heads
|
| 38 |
+
self.dropout = dropout
|
| 39 |
+
self.attention_dropout = attention_dropout
|
| 40 |
+
self.activation_dropout = activation_dropout
|
| 41 |
+
self.activation_fn = activation_fn
|
| 42 |
+
self.max_positions = max_positions
|
| 43 |
+
self.mask_idx = mask_idx
|
| 44 |
+
self.num_segments = num_segments
|
| 45 |
+
self.model_max_length = model_max_length
|
modeling_ernierna.py
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import math
|
| 2 |
+
import torch
|
| 3 |
+
import torch.nn as nn
|
| 4 |
+
import torch.nn.functional as F
|
| 5 |
+
|
| 6 |
+
from transformers import PreTrainedModel
|
| 7 |
+
from transformers.activations import ACT2FN
|
| 8 |
+
from transformers.modeling_outputs import BaseModelOutput, MaskedLMOutput
|
| 9 |
+
|
| 10 |
+
try:
|
| 11 |
+
from .configuration_ernierna import ErnieRNAConfig
|
| 12 |
+
except ImportError:
|
| 13 |
+
from configuration_ernierna import ErnieRNAConfig
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
class ErnieRNASinusoidalPositionalEmbedding(nn.Module):
|
| 17 |
+
def __init__(self, num_positions, embed_dim, padding_idx):
|
| 18 |
+
super().__init__()
|
| 19 |
+
self.embedding_dim = embed_dim
|
| 20 |
+
self.padding_idx = padding_idx
|
| 21 |
+
# Table size: need indices up to padding_idx + 1 + num_positions
|
| 22 |
+
table_size = padding_idx + 1 + num_positions
|
| 23 |
+
self.register_buffer("weights", self._get_embedding(table_size, embed_dim, padding_idx))
|
| 24 |
+
|
| 25 |
+
@staticmethod
|
| 26 |
+
def _get_embedding(num_embeddings, embedding_dim, padding_idx):
|
| 27 |
+
half_dim = embedding_dim // 2
|
| 28 |
+
emb = math.log(10000) / (half_dim - 1)
|
| 29 |
+
emb = torch.exp(torch.arange(half_dim, dtype=torch.float) * -emb)
|
| 30 |
+
emb = torch.arange(num_embeddings, dtype=torch.float).unsqueeze(1) * emb.unsqueeze(0)
|
| 31 |
+
emb = torch.cat([torch.sin(emb), torch.cos(emb)], dim=1).view(num_embeddings, -1)
|
| 32 |
+
if embedding_dim % 2 == 1:
|
| 33 |
+
emb = torch.cat([emb, torch.zeros(num_embeddings, 1)], dim=1)
|
| 34 |
+
if padding_idx is not None:
|
| 35 |
+
emb[padding_idx, :] = 0
|
| 36 |
+
return emb
|
| 37 |
+
|
| 38 |
+
def forward(self, input_ids):
|
| 39 |
+
mask = input_ids.ne(self.padding_idx).int()
|
| 40 |
+
positions = (torch.cumsum(mask, dim=1) * mask).long() + self.padding_idx
|
| 41 |
+
return self.weights.index_select(0, positions.view(-1)).view(
|
| 42 |
+
input_ids.shape[0], input_ids.shape[1], -1
|
| 43 |
+
).detach()
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
class ErnieRNATwodProj(nn.Module):
|
| 47 |
+
def __init__(self, config):
|
| 48 |
+
super().__init__()
|
| 49 |
+
self.linear1 = nn.Linear(1, 6)
|
| 50 |
+
self.linear2 = nn.Linear(6, config.attention_heads)
|
| 51 |
+
self.activation_fn = ACT2FN[config.activation_fn]
|
| 52 |
+
|
| 53 |
+
def forward(self, x):
|
| 54 |
+
x = self.linear1(x)
|
| 55 |
+
x = self.activation_fn(x)
|
| 56 |
+
x = self.linear2(x)
|
| 57 |
+
return x
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def _compute_pairing_bias(input_ids):
|
| 61 |
+
B, T = input_ids.shape
|
| 62 |
+
xi = input_ids.unsqueeze(2).expand(B, T, T)
|
| 63 |
+
xj = input_ids.unsqueeze(1).expand(B, T, T)
|
| 64 |
+
|
| 65 |
+
score = torch.zeros(B, T, T, dtype=torch.float32, device=input_ids.device)
|
| 66 |
+
score[(xi == 5) & (xj == 6)] = 2.0
|
| 67 |
+
score[(xi == 6) & (xj == 5)] = 2.0
|
| 68 |
+
score[(xi == 4) & (xj == 7)] = 3.0
|
| 69 |
+
score[(xi == 7) & (xj == 4)] = 3.0
|
| 70 |
+
score[(xi == 4) & (xj == 6)] = 0.8
|
| 71 |
+
score[(xi == 6) & (xj == 4)] = 0.8
|
| 72 |
+
return score.unsqueeze(-1) # [B, T, T, 1]
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
class ErnieRNAAttention(nn.Module):
|
| 76 |
+
def __init__(self, config):
|
| 77 |
+
super().__init__()
|
| 78 |
+
self.embed_dim = config.embed_dim
|
| 79 |
+
self.num_heads = config.attention_heads
|
| 80 |
+
self.head_dim = self.embed_dim // self.num_heads
|
| 81 |
+
assert self.head_dim * self.num_heads == self.embed_dim
|
| 82 |
+
|
| 83 |
+
self.q_proj = nn.Linear(self.embed_dim, self.embed_dim)
|
| 84 |
+
self.k_proj = nn.Linear(self.embed_dim, self.embed_dim)
|
| 85 |
+
self.v_proj = nn.Linear(self.embed_dim, self.embed_dim)
|
| 86 |
+
self.out_proj = nn.Linear(self.embed_dim, self.embed_dim)
|
| 87 |
+
self.dropout = nn.Dropout(config.attention_dropout)
|
| 88 |
+
|
| 89 |
+
def _to_bh_t_hd(self, tensor, tgt_len, bsz):
|
| 90 |
+
return tensor.contiguous().view(tgt_len, bsz * self.num_heads, self.head_dim).transpose(0, 1)
|
| 91 |
+
|
| 92 |
+
def forward(self, x, key_padding_mask=None, twod_bias=None, output_attentions=False):
|
| 93 |
+
tgt_len, bsz, _ = x.size()
|
| 94 |
+
|
| 95 |
+
q = self._to_bh_t_hd(self.q_proj(x), tgt_len, bsz)
|
| 96 |
+
k = self._to_bh_t_hd(self.k_proj(x), tgt_len, bsz)
|
| 97 |
+
v = self._to_bh_t_hd(self.v_proj(x), tgt_len, bsz)
|
| 98 |
+
|
| 99 |
+
scale = self.head_dim ** -0.5
|
| 100 |
+
q = q * scale
|
| 101 |
+
|
| 102 |
+
attn_weights = torch.bmm(q, k.transpose(-2, -1)) # [B*H, T, T]
|
| 103 |
+
|
| 104 |
+
if key_padding_mask is not None:
|
| 105 |
+
attn_weights = attn_weights.view(bsz, self.num_heads, tgt_len, tgt_len)
|
| 106 |
+
attn_weights = attn_weights.masked_fill(
|
| 107 |
+
key_padding_mask.unsqueeze(1).unsqueeze(2), float("-inf")
|
| 108 |
+
)
|
| 109 |
+
attn_weights = attn_weights.view(bsz * self.num_heads, tgt_len, tgt_len)
|
| 110 |
+
|
| 111 |
+
if twod_bias is not None:
|
| 112 |
+
attn_weights = attn_weights + twod_bias.reshape(bsz * self.num_heads, tgt_len, tgt_len)
|
| 113 |
+
|
| 114 |
+
# Pre-softmax attention becomes the 2D bias for the next layer
|
| 115 |
+
twod_bias_new = attn_weights.view(bsz, self.num_heads, tgt_len, tgt_len)
|
| 116 |
+
|
| 117 |
+
attn_probs = F.softmax(attn_weights, dim=-1)
|
| 118 |
+
attn_weights_out = None
|
| 119 |
+
if output_attentions:
|
| 120 |
+
attn_weights_out = attn_probs.view(bsz, self.num_heads, tgt_len, tgt_len)
|
| 121 |
+
attn_probs = self.dropout(attn_probs)
|
| 122 |
+
|
| 123 |
+
out = torch.bmm(attn_probs, v)
|
| 124 |
+
out = out.transpose(0, 1).contiguous().view(tgt_len, bsz, self.embed_dim)
|
| 125 |
+
out = self.out_proj(out)
|
| 126 |
+
|
| 127 |
+
return out, attn_weights_out, twod_bias_new
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
class ErnieRNALayer(nn.Module):
|
| 131 |
+
def __init__(self, config):
|
| 132 |
+
super().__init__()
|
| 133 |
+
self.self_attn = ErnieRNAAttention(config)
|
| 134 |
+
self.self_attn_layer_norm = nn.LayerNorm(config.embed_dim)
|
| 135 |
+
self.fc1 = nn.Linear(config.embed_dim, config.ffn_embed_dim)
|
| 136 |
+
self.fc2 = nn.Linear(config.ffn_embed_dim, config.embed_dim)
|
| 137 |
+
self.final_layer_norm = nn.LayerNorm(config.embed_dim)
|
| 138 |
+
self.dropout = nn.Dropout(config.dropout)
|
| 139 |
+
self.activation_dropout = nn.Dropout(config.activation_dropout)
|
| 140 |
+
self.activation_fn = ACT2FN[config.activation_fn]
|
| 141 |
+
|
| 142 |
+
def forward(self, x, key_padding_mask=None, twod_bias=None, output_attentions=False):
|
| 143 |
+
residual = x
|
| 144 |
+
x, attn_weights, twod_bias_new = self.self_attn(
|
| 145 |
+
x,
|
| 146 |
+
key_padding_mask=key_padding_mask,
|
| 147 |
+
twod_bias=twod_bias,
|
| 148 |
+
output_attentions=output_attentions,
|
| 149 |
+
)
|
| 150 |
+
x = self.dropout(x)
|
| 151 |
+
x = self.self_attn_layer_norm(residual + x)
|
| 152 |
+
|
| 153 |
+
residual = x
|
| 154 |
+
x = self.activation_fn(self.fc1(x))
|
| 155 |
+
x = self.activation_dropout(x)
|
| 156 |
+
x = self.fc2(x)
|
| 157 |
+
x = self.dropout(x)
|
| 158 |
+
x = self.final_layer_norm(residual + x)
|
| 159 |
+
|
| 160 |
+
return x, attn_weights, twod_bias_new
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
class ErnieRNAModel(PreTrainedModel):
|
| 164 |
+
config_class = ErnieRNAConfig
|
| 165 |
+
base_model_prefix = "model"
|
| 166 |
+
_supports_sdpa = False
|
| 167 |
+
_supports_flash_attn_2 = False
|
| 168 |
+
|
| 169 |
+
def __init__(self, config):
|
| 170 |
+
super().__init__(config)
|
| 171 |
+
self.padding_idx = config.padding_idx
|
| 172 |
+
|
| 173 |
+
self.embed_tokens = nn.Embedding(config.vocab_size, config.embed_dim, padding_idx=config.padding_idx)
|
| 174 |
+
self.embed_positions = ErnieRNASinusoidalPositionalEmbedding(
|
| 175 |
+
config.max_positions, config.embed_dim, config.padding_idx
|
| 176 |
+
)
|
| 177 |
+
self.segment_embeddings = nn.Embedding(config.num_segments, config.embed_dim)
|
| 178 |
+
self.emb_layer_norm = nn.LayerNorm(config.embed_dim)
|
| 179 |
+
self.dropout = nn.Dropout(config.dropout)
|
| 180 |
+
self.layers = nn.ModuleList([ErnieRNALayer(config) for _ in range(config.num_layers)])
|
| 181 |
+
self.twod_proj = ErnieRNATwodProj(config)
|
| 182 |
+
|
| 183 |
+
self.post_init()
|
| 184 |
+
|
| 185 |
+
def forward(
|
| 186 |
+
self,
|
| 187 |
+
input_ids=None,
|
| 188 |
+
attention_mask=None,
|
| 189 |
+
token_type_ids=None,
|
| 190 |
+
output_attentions=None,
|
| 191 |
+
output_hidden_states=None,
|
| 192 |
+
return_dict=None,
|
| 193 |
+
):
|
| 194 |
+
output_attentions = output_attentions if output_attentions is not None else self.config.output_attentions
|
| 195 |
+
output_hidden_states = output_hidden_states if output_hidden_states is not None else self.config.output_hidden_states
|
| 196 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 197 |
+
|
| 198 |
+
# HF: 1=attend, 0=pad -> True=padding
|
| 199 |
+
if attention_mask is not None:
|
| 200 |
+
padding_mask = attention_mask.eq(0)
|
| 201 |
+
else:
|
| 202 |
+
padding_mask = input_ids.eq(self.padding_idx)
|
| 203 |
+
|
| 204 |
+
# Zero out padding positions after masking (matches fairseq behavior)
|
| 205 |
+
x = self.embed_tokens(input_ids)
|
| 206 |
+
# Sinusoidal PE is a float32 buffer; cast to activation dtype for bfloat16 compat.
|
| 207 |
+
x = x + self.embed_positions(input_ids).to(x.dtype)
|
| 208 |
+
if token_type_ids is not None:
|
| 209 |
+
x = x + self.segment_embeddings(token_type_ids)
|
| 210 |
+
x = self.emb_layer_norm(x)
|
| 211 |
+
if padding_mask.any():
|
| 212 |
+
x = x * (~padding_mask).unsqueeze(-1).to(x.dtype)
|
| 213 |
+
x = self.dropout(x)
|
| 214 |
+
|
| 215 |
+
# Compute initial 2D bias from sequence (always float32 as in original)
|
| 216 |
+
pairing = _compute_pairing_bias(input_ids) # [B, T, T, 1]
|
| 217 |
+
twod_proj_f32 = self.twod_proj.float()
|
| 218 |
+
twod_bias = twod_proj_f32(pairing.float()) # [B, T, T, H]
|
| 219 |
+
twod_bias = twod_bias.permute(0, 3, 1, 2).contiguous().to(x.dtype) # [B, H, T, T]
|
| 220 |
+
|
| 221 |
+
# Transpose to [T, B, C] for attention
|
| 222 |
+
x = x.transpose(0, 1)
|
| 223 |
+
|
| 224 |
+
all_hidden_states = []
|
| 225 |
+
all_attentions = []
|
| 226 |
+
|
| 227 |
+
if output_hidden_states:
|
| 228 |
+
all_hidden_states.append(x.transpose(0, 1))
|
| 229 |
+
|
| 230 |
+
key_padding_mask = padding_mask if padding_mask.any() else None
|
| 231 |
+
|
| 232 |
+
for layer in self.layers:
|
| 233 |
+
x, attn_weights, twod_bias = layer(
|
| 234 |
+
x,
|
| 235 |
+
key_padding_mask=key_padding_mask,
|
| 236 |
+
twod_bias=twod_bias,
|
| 237 |
+
output_attentions=output_attentions,
|
| 238 |
+
)
|
| 239 |
+
if output_hidden_states:
|
| 240 |
+
all_hidden_states.append(x.transpose(0, 1))
|
| 241 |
+
if output_attentions:
|
| 242 |
+
all_attentions.append(attn_weights)
|
| 243 |
+
|
| 244 |
+
x = x.transpose(0, 1) # [B, T, C]
|
| 245 |
+
|
| 246 |
+
if not return_dict:
|
| 247 |
+
return tuple(v for v in [x, tuple(all_hidden_states) or None, tuple(all_attentions) or None] if v is not None)
|
| 248 |
+
|
| 249 |
+
return BaseModelOutput(
|
| 250 |
+
last_hidden_state=x,
|
| 251 |
+
hidden_states=tuple(all_hidden_states) if output_hidden_states else None,
|
| 252 |
+
attentions=tuple(all_attentions) if output_attentions else None,
|
| 253 |
+
)
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
class ErnieRNALMHead(nn.Module):
|
| 257 |
+
def __init__(self, config):
|
| 258 |
+
super().__init__()
|
| 259 |
+
self.dense = nn.Linear(config.embed_dim, config.embed_dim)
|
| 260 |
+
self.layer_norm = nn.LayerNorm(config.embed_dim)
|
| 261 |
+
self.activation_fn = ACT2FN[config.activation_fn]
|
| 262 |
+
self.decoder = nn.Linear(config.embed_dim, config.vocab_size)
|
| 263 |
+
|
| 264 |
+
def forward(self, x):
|
| 265 |
+
x = self.layer_norm(self.activation_fn(self.dense(x)))
|
| 266 |
+
x = self.decoder(x)
|
| 267 |
+
return x
|
| 268 |
+
|
| 269 |
+
|
| 270 |
+
class ErnieRNAForMaskedLM(PreTrainedModel):
|
| 271 |
+
config_class = ErnieRNAConfig
|
| 272 |
+
base_model_prefix = "model"
|
| 273 |
+
_supports_sdpa = False
|
| 274 |
+
_supports_flash_attn_2 = False
|
| 275 |
+
|
| 276 |
+
def __init__(self, config):
|
| 277 |
+
super().__init__(config)
|
| 278 |
+
self.model = ErnieRNAModel(config)
|
| 279 |
+
self.lm_head = ErnieRNALMHead(config)
|
| 280 |
+
self.post_init()
|
| 281 |
+
|
| 282 |
+
def forward(
|
| 283 |
+
self,
|
| 284 |
+
input_ids=None,
|
| 285 |
+
attention_mask=None,
|
| 286 |
+
token_type_ids=None,
|
| 287 |
+
labels=None,
|
| 288 |
+
output_attentions=None,
|
| 289 |
+
output_hidden_states=None,
|
| 290 |
+
return_dict=None,
|
| 291 |
+
):
|
| 292 |
+
return_dict = return_dict if return_dict is not None else self.config.use_return_dict
|
| 293 |
+
|
| 294 |
+
out = self.model(
|
| 295 |
+
input_ids,
|
| 296 |
+
attention_mask=attention_mask,
|
| 297 |
+
token_type_ids=token_type_ids,
|
| 298 |
+
output_attentions=output_attentions,
|
| 299 |
+
output_hidden_states=output_hidden_states,
|
| 300 |
+
return_dict=return_dict,
|
| 301 |
+
)
|
| 302 |
+
|
| 303 |
+
logits = self.lm_head(out[0])
|
| 304 |
+
|
| 305 |
+
loss = None
|
| 306 |
+
if labels is not None:
|
| 307 |
+
loss = F.cross_entropy(
|
| 308 |
+
logits.view(-1, self.config.vocab_size),
|
| 309 |
+
labels.view(-1),
|
| 310 |
+
ignore_index=-100,
|
| 311 |
+
)
|
| 312 |
+
|
| 313 |
+
if not return_dict:
|
| 314 |
+
output = (logits,) + out[1:]
|
| 315 |
+
return ((loss,) + output) if loss is not None else output
|
| 316 |
+
|
| 317 |
+
return MaskedLMOutput(
|
| 318 |
+
loss=loss,
|
| 319 |
+
logits=logits,
|
| 320 |
+
hidden_states=out.hidden_states,
|
| 321 |
+
attentions=out.attentions,
|
| 322 |
+
)
|
pytorch_model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:10de02fd6d0034cd2e6987abffb3abafad75ac0c7420697d0572c45c4fac1bfb
|
| 3 |
+
size 345970527
|
special_tokens_map.json
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"cls_token": "<cls>",
|
| 3 |
+
"eos_token": "<eos>",
|
| 4 |
+
"mask_token": "<mask>",
|
| 5 |
+
"pad_token": "<pad>",
|
| 6 |
+
"unk_token": "<unk>"
|
| 7 |
+
}
|
tokenization_ernierna.py
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
import os
|
| 3 |
+
from transformers import PreTrainedTokenizer
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
_VOCAB = {
|
| 7 |
+
"<cls>": 0,
|
| 8 |
+
"<pad>": 1,
|
| 9 |
+
"<eos>": 2,
|
| 10 |
+
"<unk>": 3,
|
| 11 |
+
"G": 4,
|
| 12 |
+
"A": 5,
|
| 13 |
+
"U": 6,
|
| 14 |
+
"C": 7,
|
| 15 |
+
"N": 8,
|
| 16 |
+
"Y": 9,
|
| 17 |
+
"R": 10,
|
| 18 |
+
"S": 11,
|
| 19 |
+
"K": 12,
|
| 20 |
+
"W": 13,
|
| 21 |
+
"M": 14,
|
| 22 |
+
"D": 15,
|
| 23 |
+
"H": 16,
|
| 24 |
+
"V": 17,
|
| 25 |
+
"B": 18,
|
| 26 |
+
"X": 19,
|
| 27 |
+
"I": 20,
|
| 28 |
+
"madeupword0000": 21,
|
| 29 |
+
"madeupword0001": 22,
|
| 30 |
+
"madeupword0002": 23,
|
| 31 |
+
"<mask>": 24,
|
| 32 |
+
}
|
| 33 |
+
|
| 34 |
+
|
| 35 |
+
class ErnieRNATokenizer(PreTrainedTokenizer):
|
| 36 |
+
vocab_files_names = {"vocab_file": "vocab.json"}
|
| 37 |
+
model_input_names = ["input_ids", "attention_mask"]
|
| 38 |
+
|
| 39 |
+
def __init__(
|
| 40 |
+
self,
|
| 41 |
+
vocab_file=None,
|
| 42 |
+
cls_token="<cls>",
|
| 43 |
+
pad_token="<pad>",
|
| 44 |
+
eos_token="<eos>",
|
| 45 |
+
unk_token="<unk>",
|
| 46 |
+
mask_token="<mask>",
|
| 47 |
+
**kwargs,
|
| 48 |
+
):
|
| 49 |
+
if vocab_file is not None and os.path.isfile(vocab_file):
|
| 50 |
+
with open(vocab_file) as f:
|
| 51 |
+
self._vocab = json.load(f)
|
| 52 |
+
else:
|
| 53 |
+
self._vocab = dict(_VOCAB)
|
| 54 |
+
self._ids_to_tokens = {v: k for k, v in self._vocab.items()}
|
| 55 |
+
|
| 56 |
+
super().__init__(
|
| 57 |
+
cls_token=cls_token,
|
| 58 |
+
pad_token=pad_token,
|
| 59 |
+
eos_token=eos_token,
|
| 60 |
+
unk_token=unk_token,
|
| 61 |
+
mask_token=mask_token,
|
| 62 |
+
**kwargs,
|
| 63 |
+
)
|
| 64 |
+
|
| 65 |
+
@property
|
| 66 |
+
def vocab_size(self):
|
| 67 |
+
return len(self._vocab)
|
| 68 |
+
|
| 69 |
+
def get_vocab(self):
|
| 70 |
+
return dict(self._vocab)
|
| 71 |
+
|
| 72 |
+
def _tokenize(self, text):
|
| 73 |
+
tokens = []
|
| 74 |
+
for ch in text.upper():
|
| 75 |
+
if ch == "T":
|
| 76 |
+
tokens.append("U")
|
| 77 |
+
elif ch in self._vocab:
|
| 78 |
+
tokens.append(ch)
|
| 79 |
+
else:
|
| 80 |
+
tokens.append("<unk>")
|
| 81 |
+
return tokens
|
| 82 |
+
|
| 83 |
+
def _convert_token_to_id(self, token):
|
| 84 |
+
return self._vocab.get(token, self._vocab["<unk>"])
|
| 85 |
+
|
| 86 |
+
def _convert_id_to_token(self, index):
|
| 87 |
+
return self._ids_to_tokens.get(index, "<unk>")
|
| 88 |
+
|
| 89 |
+
def save_vocabulary(self, save_directory, filename_prefix=None):
|
| 90 |
+
os.makedirs(save_directory, exist_ok=True)
|
| 91 |
+
fname = (filename_prefix + "-" if filename_prefix else "") + "vocab.json"
|
| 92 |
+
path = os.path.join(save_directory, fname)
|
| 93 |
+
with open(path, "w") as f:
|
| 94 |
+
json.dump(self._vocab, f, indent=2)
|
| 95 |
+
return (path,)
|
| 96 |
+
|
| 97 |
+
def build_inputs_with_special_tokens(self, token_ids_0, token_ids_1=None):
|
| 98 |
+
cls = [self.cls_token_id]
|
| 99 |
+
eos = [self.eos_token_id]
|
| 100 |
+
if token_ids_1 is None:
|
| 101 |
+
return cls + token_ids_0 + eos
|
| 102 |
+
return cls + token_ids_0 + eos + cls + token_ids_1 + eos
|
| 103 |
+
|
| 104 |
+
def get_special_tokens_mask(self, token_ids_0, token_ids_1=None, already_has_special_tokens=False):
|
| 105 |
+
if already_has_special_tokens:
|
| 106 |
+
return super().get_special_tokens_mask(token_ids_0, token_ids_1, already_has_special_tokens=True)
|
| 107 |
+
mask = [1] + [0] * len(token_ids_0) + [1]
|
| 108 |
+
if token_ids_1 is not None:
|
| 109 |
+
mask += [1] + [0] * len(token_ids_1) + [1]
|
| 110 |
+
return mask
|
| 111 |
+
|
| 112 |
+
def create_token_type_ids_from_sequences(self, token_ids_0, token_ids_1=None):
|
| 113 |
+
if token_ids_1 is None:
|
| 114 |
+
return [0] + token_ids_0 + [0]
|
| 115 |
+
return [0] + token_ids_0 + [0, 0] + token_ids_1 + [0]
|
tokenizer_config.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"added_tokens_decoder": {
|
| 3 |
+
"0": {
|
| 4 |
+
"content": "<cls>",
|
| 5 |
+
"lstrip": false,
|
| 6 |
+
"normalized": false,
|
| 7 |
+
"rstrip": false,
|
| 8 |
+
"single_word": false,
|
| 9 |
+
"special": true
|
| 10 |
+
},
|
| 11 |
+
"1": {
|
| 12 |
+
"content": "<pad>",
|
| 13 |
+
"lstrip": false,
|
| 14 |
+
"normalized": false,
|
| 15 |
+
"rstrip": false,
|
| 16 |
+
"single_word": false,
|
| 17 |
+
"special": true
|
| 18 |
+
},
|
| 19 |
+
"2": {
|
| 20 |
+
"content": "<eos>",
|
| 21 |
+
"lstrip": false,
|
| 22 |
+
"normalized": false,
|
| 23 |
+
"rstrip": false,
|
| 24 |
+
"single_word": false,
|
| 25 |
+
"special": true
|
| 26 |
+
},
|
| 27 |
+
"3": {
|
| 28 |
+
"content": "<unk>",
|
| 29 |
+
"lstrip": false,
|
| 30 |
+
"normalized": false,
|
| 31 |
+
"rstrip": false,
|
| 32 |
+
"single_word": false,
|
| 33 |
+
"special": true
|
| 34 |
+
},
|
| 35 |
+
"24": {
|
| 36 |
+
"content": "<mask>",
|
| 37 |
+
"lstrip": false,
|
| 38 |
+
"normalized": false,
|
| 39 |
+
"rstrip": false,
|
| 40 |
+
"single_word": false,
|
| 41 |
+
"special": true
|
| 42 |
+
}
|
| 43 |
+
},
|
| 44 |
+
"clean_up_tokenization_spaces": false,
|
| 45 |
+
"cls_token": "<cls>",
|
| 46 |
+
"eos_token": "<eos>",
|
| 47 |
+
"extra_special_tokens": {},
|
| 48 |
+
"mask_token": "<mask>",
|
| 49 |
+
"auto_map": {
|
| 50 |
+
"AutoTokenizer": ["tokenization_ernierna.ErnieRNATokenizer", null]
|
| 51 |
+
},
|
| 52 |
+
"model_max_length": 1024,
|
| 53 |
+
"pad_token": "<pad>",
|
| 54 |
+
"tokenizer_class": "ErnieRNATokenizer",
|
| 55 |
+
"unk_token": "<unk>"
|
| 56 |
+
}
|
vocab.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"<cls>": 0,
|
| 3 |
+
"<pad>": 1,
|
| 4 |
+
"<eos>": 2,
|
| 5 |
+
"<unk>": 3,
|
| 6 |
+
"G": 4,
|
| 7 |
+
"A": 5,
|
| 8 |
+
"U": 6,
|
| 9 |
+
"C": 7,
|
| 10 |
+
"N": 8,
|
| 11 |
+
"Y": 9,
|
| 12 |
+
"R": 10,
|
| 13 |
+
"S": 11,
|
| 14 |
+
"K": 12,
|
| 15 |
+
"W": 13,
|
| 16 |
+
"M": 14,
|
| 17 |
+
"D": 15,
|
| 18 |
+
"H": 16,
|
| 19 |
+
"V": 17,
|
| 20 |
+
"B": 18,
|
| 21 |
+
"X": 19,
|
| 22 |
+
"I": 20,
|
| 23 |
+
"madeupword0000": 21,
|
| 24 |
+
"madeupword0001": 22,
|
| 25 |
+
"madeupword0002": 23,
|
| 26 |
+
"<mask>": 24
|
| 27 |
+
}
|