sledgedev commited on
Commit
955cc5d
·
verified ·
1 Parent(s): fe40c24

Add/update rampart_mlx.py

Browse files
Files changed (1) hide show
  1. rampart_mlx.py +155 -0
rampart_mlx.py ADDED
@@ -0,0 +1,155 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Rampart BERT-for-token-classification in MLX.
2
+
3
+ Mirrors HuggingFace `BertForTokenClassification` (MiniLM-L6-H384) so the float
4
+ weights extracted from the ONNX model load 1:1, and so the same module can be
5
+ quantized with mlx and re-exported for mlx-swift.
6
+ """
7
+ import json
8
+ import mlx.core as mx
9
+ import mlx.nn as nn
10
+
11
+
12
+ class BertConfig:
13
+ def __init__(self, **kw):
14
+ self.vocab_size = kw["vocab_size"]
15
+ self.hidden_size = kw["hidden_size"]
16
+ self.num_hidden_layers = kw["num_hidden_layers"]
17
+ self.num_attention_heads = kw["num_attention_heads"]
18
+ self.intermediate_size = kw["intermediate_size"]
19
+ self.max_position_embeddings = kw["max_position_embeddings"]
20
+ self.type_vocab_size = kw["type_vocab_size"]
21
+ self.layer_norm_eps = kw.get("layer_norm_eps", 1e-12)
22
+ self.num_labels = len(kw["id2label"])
23
+ self.id2label = {int(k): v for k, v in kw["id2label"].items()}
24
+
25
+ @classmethod
26
+ def from_json(cls, path):
27
+ with open(path) as f:
28
+ return cls(**json.load(f))
29
+
30
+
31
+ class BertEmbeddings(nn.Module):
32
+ def __init__(self, c: BertConfig):
33
+ super().__init__()
34
+ self.word_embeddings = nn.Embedding(c.vocab_size, c.hidden_size)
35
+ self.position_embeddings = nn.Embedding(c.max_position_embeddings, c.hidden_size)
36
+ self.token_type_embeddings = nn.Embedding(c.type_vocab_size, c.hidden_size)
37
+ self.LayerNorm = nn.LayerNorm(c.hidden_size, eps=c.layer_norm_eps)
38
+
39
+ def __call__(self, input_ids, token_type_ids):
40
+ seq = input_ids.shape[1]
41
+ pos = mx.arange(seq)[None, :]
42
+ e = (self.word_embeddings(input_ids)
43
+ + self.position_embeddings(pos)
44
+ + self.token_type_embeddings(token_type_ids))
45
+ return self.LayerNorm(e)
46
+
47
+
48
+ class BertSelfAttention(nn.Module):
49
+ def __init__(self, c: BertConfig):
50
+ super().__init__()
51
+ self.num_heads = c.num_attention_heads
52
+ self.head_dim = c.hidden_size // c.num_attention_heads
53
+ self.query = nn.Linear(c.hidden_size, c.hidden_size)
54
+ self.key = nn.Linear(c.hidden_size, c.hidden_size)
55
+ self.value = nn.Linear(c.hidden_size, c.hidden_size)
56
+
57
+ def __call__(self, x, mask):
58
+ B, L, _ = x.shape
59
+ H, D = self.num_heads, self.head_dim
60
+ def shape(t):
61
+ return t.reshape(B, L, H, D).transpose(0, 2, 1, 3)
62
+ q, k, v = shape(self.query(x)), shape(self.key(x)), shape(self.value(x))
63
+ scores = (q @ k.transpose(0, 1, 3, 2)) * (1.0 / (D ** 0.5))
64
+ scores = scores + mask # mask: [B,1,1,L] additive
65
+ probs = mx.softmax(scores, axis=-1)
66
+ ctx = (probs @ v).transpose(0, 2, 1, 3).reshape(B, L, H * D)
67
+ return ctx
68
+
69
+
70
+ class BertAttention(nn.Module):
71
+ def __init__(self, c: BertConfig):
72
+ super().__init__()
73
+ self.self = BertSelfAttention(c)
74
+ self.output = BertSelfOutput(c)
75
+
76
+ def __call__(self, x, mask):
77
+ return self.output(self.self(x, mask), x)
78
+
79
+
80
+ class BertSelfOutput(nn.Module):
81
+ def __init__(self, c: BertConfig):
82
+ super().__init__()
83
+ self.dense = nn.Linear(c.hidden_size, c.hidden_size)
84
+ self.LayerNorm = nn.LayerNorm(c.hidden_size, eps=c.layer_norm_eps)
85
+
86
+ def __call__(self, x, residual):
87
+ return self.LayerNorm(self.dense(x) + residual)
88
+
89
+
90
+ class BertIntermediate(nn.Module):
91
+ def __init__(self, c: BertConfig):
92
+ super().__init__()
93
+ self.dense = nn.Linear(c.hidden_size, c.intermediate_size)
94
+
95
+ def __call__(self, x):
96
+ return nn.gelu(self.dense(x))
97
+
98
+
99
+ class BertOutput(nn.Module):
100
+ def __init__(self, c: BertConfig):
101
+ super().__init__()
102
+ self.dense = nn.Linear(c.intermediate_size, c.hidden_size)
103
+ self.LayerNorm = nn.LayerNorm(c.hidden_size, eps=c.layer_norm_eps)
104
+
105
+ def __call__(self, x, residual):
106
+ return self.LayerNorm(self.dense(x) + residual)
107
+
108
+
109
+ class BertLayer(nn.Module):
110
+ def __init__(self, c: BertConfig):
111
+ super().__init__()
112
+ self.attention = BertAttention(c)
113
+ self.intermediate = BertIntermediate(c)
114
+ self.output = BertOutput(c)
115
+
116
+ def __call__(self, x, mask):
117
+ a = self.attention(x, mask)
118
+ return self.output(self.intermediate(a), a)
119
+
120
+
121
+ class BertEncoder(nn.Module):
122
+ def __init__(self, c: BertConfig):
123
+ super().__init__()
124
+ self.layer = [BertLayer(c) for _ in range(c.num_hidden_layers)]
125
+
126
+ def __call__(self, x, mask):
127
+ for lyr in self.layer:
128
+ x = lyr(x, mask)
129
+ return x
130
+
131
+
132
+ class BertModel(nn.Module):
133
+ def __init__(self, c: BertConfig):
134
+ super().__init__()
135
+ self.embeddings = BertEmbeddings(c)
136
+ self.encoder = BertEncoder(c)
137
+
138
+ def __call__(self, input_ids, token_type_ids, mask):
139
+ h = self.embeddings(input_ids, token_type_ids)
140
+ return self.encoder(h, mask)
141
+
142
+
143
+ class RampartForTokenClassification(nn.Module):
144
+ def __init__(self, c: BertConfig):
145
+ super().__init__()
146
+ self.config = c
147
+ self.bert = BertModel(c)
148
+ self.classifier = nn.Linear(c.hidden_size, c.num_labels)
149
+
150
+ def __call__(self, input_ids, attention_mask, token_type_ids=None):
151
+ if token_type_ids is None:
152
+ token_type_ids = mx.zeros_like(input_ids)
153
+ mask = (1.0 - attention_mask.astype(mx.float32))[:, None, None, :] * -1e9
154
+ h = self.bert(input_ids, token_type_ids, mask)
155
+ return self.classifier(h)