|
3 | 3 |
|
4 | 4 | from thinc.api import ( |
5 | 5 | Dropout, |
| 6 | + Gelu, |
6 | 7 | LayerNorm, |
7 | 8 | Linear, |
8 | 9 | Logistic, |
9 | 10 | Maxout, |
10 | 11 | Model, |
11 | 12 | ParametricAttention, |
| 13 | + ParametricAttention_v2, |
12 | 14 | Relu, |
13 | 15 | Softmax, |
14 | 16 | SparseLinear, |
@@ -146,6 +148,9 @@ def build_text_classifier_v2( |
146 | 148 | linear_model: Model[List[Doc], Floats2d], |
147 | 149 | nO: Optional[int] = None, |
148 | 150 | ) -> Model[List[Doc], Floats2d]: |
| 151 | + # TODO: build the model with _build_parametric_attention_with_residual_nonlinear |
| 152 | + # in spaCy v4. We don't do this in spaCy v3 to preserve model |
| 153 | + # compatibility. |
149 | 154 | exclusive_classes = not linear_model.attrs["multi_label"] |
150 | 155 | with Model.define_operators({">>": chain, "|": concatenate}): |
151 | 156 | width = tok2vec.maybe_get_dim("nO") |
@@ -211,6 +216,71 @@ def build_text_classifier_lowdata( |
211 | 216 | return model |
212 | 217 |
|
213 | 218 |
|
| 219 | +@registry.architectures("spacy.TextCatParametricAttention.v1") |
| 220 | +def build_textcat_parametric_attention_v1( |
| 221 | + tok2vec: Model[List[Doc], List[Floats2d]], |
| 222 | + exclusive_classes: bool, |
| 223 | + nO: Optional[int] = None, |
| 224 | +) -> Model[List[Doc], Floats2d]: |
| 225 | + width = tok2vec.maybe_get_dim("nO") |
| 226 | + parametric_attention = _build_parametric_attention_with_residual_nonlinear( |
| 227 | + tok2vec=tok2vec, |
| 228 | + nonlinear_layer=Maxout(nI=width, nO=width), |
| 229 | + key_transform=Gelu(nI=width, nO=width), |
| 230 | + ) |
| 231 | + with Model.define_operators({">>": chain}): |
| 232 | + if exclusive_classes: |
| 233 | + output_layer = Softmax(nO=nO) |
| 234 | + else: |
| 235 | + output_layer = Linear(nO=nO) >> Logistic() |
| 236 | + model = parametric_attention >> output_layer |
| 237 | + if model.has_dim("nO") is not False and nO is not None: |
| 238 | + model.set_dim("nO", cast(int, nO)) |
| 239 | + model.set_ref("output_layer", output_layer) |
| 240 | + model.attrs["multi_label"] = not exclusive_classes |
| 241 | + |
| 242 | + return model |
| 243 | + |
| 244 | + |
| 245 | +def _build_parametric_attention_with_residual_nonlinear( |
| 246 | + *, |
| 247 | + tok2vec: Model[List[Doc], List[Floats2d]], |
| 248 | + nonlinear_layer: Model[Floats2d, Floats2d], |
| 249 | + key_transform: Optional[Model[Floats2d, Floats2d]] = None, |
| 250 | +) -> Model[List[Doc], Floats2d]: |
| 251 | + with Model.define_operators({">>": chain, "|": concatenate}): |
| 252 | + width = tok2vec.maybe_get_dim("nO") |
| 253 | + attention_layer = ParametricAttention_v2(nO=width, key_transform=key_transform) |
| 254 | + norm_layer = LayerNorm(nI=width) |
| 255 | + parametric_attention = ( |
| 256 | + tok2vec |
| 257 | + >> list2ragged() |
| 258 | + >> attention_layer |
| 259 | + >> reduce_sum() |
| 260 | + >> residual(nonlinear_layer >> norm_layer >> Dropout(0.0)) |
| 261 | + ) |
| 262 | + |
| 263 | + parametric_attention.init = _init_parametric_attention_with_residual_nonlinear |
| 264 | + |
| 265 | + parametric_attention.set_ref("tok2vec", tok2vec) |
| 266 | + parametric_attention.set_ref("attention_layer", attention_layer) |
| 267 | + parametric_attention.set_ref("nonlinear_layer", nonlinear_layer) |
| 268 | + parametric_attention.set_ref("norm_layer", norm_layer) |
| 269 | + |
| 270 | + return parametric_attention |
| 271 | + |
| 272 | + |
| 273 | +def _init_parametric_attention_with_residual_nonlinear(model, X, Y) -> Model: |
| 274 | + tok2vec_width = get_tok2vec_width(model) |
| 275 | + model.get_ref("attention_layer").set_dim("nO", tok2vec_width) |
| 276 | + model.get_ref("nonlinear_layer").set_dim("nO", tok2vec_width) |
| 277 | + model.get_ref("nonlinear_layer").set_dim("nI", tok2vec_width) |
| 278 | + model.get_ref("norm_layer").set_dim("nI", tok2vec_width) |
| 279 | + model.get_ref("norm_layer").set_dim("nO", tok2vec_width) |
| 280 | + init_chain(model, X, Y) |
| 281 | + return model |
| 282 | + |
| 283 | + |
214 | 284 | @registry.architectures("spacy.TextCatReduce.v1") |
215 | 285 | def build_reduce_text_classifier( |
216 | 286 | tok2vec: Model, |
|
0 commit comments