raglu 0.1.0__tar.gz

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.
raglu-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ömer Faruk Solmaz
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
raglu-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: raglu
3
+ Version: 0.1.0
4
+ Summary: Pure Rational GLU (RaGLU) and RaLU activations for PyTorch, Triton CUDA and Apple MLX.
5
+ Author: Ömer Faruk Solmaz
6
+ License-Expression: MIT
7
+ Keywords: activation,glu,ralu,rational,pytorch,triton,mlx,deep-learning
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: torch>=2.0.0
24
+ Provides-Extra: triton
25
+ Requires-Dist: triton>=2.0.0; extra == "triton"
26
+ Provides-Extra: mlx
27
+ Requires-Dist: mlx>=0.1.0; extra == "mlx"
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
30
+ Requires-Dist: build>=1.0.0; extra == "dev"
31
+ Requires-Dist: twine>=4.0.0; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # RaGLU
35
+
36
+ **Pure Rational GLU (RaGLU)** ve **RaLU** aktivasyon fonksiyonları için platform
37
+ bağımsız PyTorch kütüphanesi. NVIDIA CUDA'da isteğe bağlı **Triton** çekirdekleri,
38
+ Apple Silicon'da ise yerel **MLX** desteği sunar.
39
+
40
+ Paket iki `nn.Module` sınıfı sunar:
41
+
42
+ | Sınıf | Görevi |
43
+ | --- | --- |
44
+ | `RaGLU()` | Kapılı (GLU) katman: `Linear` çıktısını gate/val olarak ikiye böler, `f(g) * v` uygular. |
45
+ | `RaLU()` | Kapısız, element-wise aktivasyon: `f(x)` uygular, şekli değiştirmez. |
46
+
47
+ ## Fonksiyonlar
48
+
49
+ Kapılı (gated) varyant:
50
+
51
+ $$
52
+ \operatorname{RaGLU}(g, v) = \frac{g^3 + g}{g^2 + 3} \cdot v
53
+ $$
54
+
55
+ Kapısız varyant:
56
+
57
+ $$
58
+ \operatorname{RaLU}(x) = \frac{x^3 + x}{x^2 + 3}
59
+ $$
60
+
61
+ Türev (her iki varyantın çekirdeği):
62
+
63
+ $$
64
+ \frac{d}{dx}\left(\frac{x^3 + x}{x^2 + 3}\right)
65
+ = \frac{x^4 + 8x^2 + 3}{(x^2 + 3)^2}
66
+ $$
67
+
68
+ Fonksiyon tek (odd) bir fonksiyondur: `f(-x) = -f(x)`. Payda her zaman
69
+ `>= 3` olduğundan sayısal olarak kararlıdır.
70
+
71
+ ## Kurulum
72
+
73
+ ```bash
74
+ pip install raglu
75
+ ```
76
+
77
+ İsteğe bağlı hızlandırıcılar:
78
+
79
+ ```bash
80
+ pip install "raglu[triton]" # NVIDIA CUDA için Triton çekirdekleri
81
+ pip install "raglu[mlx]" # Apple Silicon için MLX
82
+ pip install "raglu[dev]" # test + derleme araçları
83
+ ```
84
+
85
+ ## Kullanım
86
+
87
+ ### Fonksiyonel PyTorch API
88
+
89
+ ```python
90
+ import torch
91
+ from raglu import fused_pure_rational_glu, fused_pure_rational
92
+
93
+ gate = torch.randn(32, 128)
94
+ val = torch.randn(32, 128)
95
+
96
+ y = fused_pure_rational_glu(gate, val) # (32, 128)
97
+ z = fused_pure_rational(gate) # (32, 128)
98
+ ```
99
+
100
+ `fused_pure_rational_glu`, CUDA + Triton mevcutsa füzyonlu çekirdeği kullanır.
101
+ Aksi halde otomatik olarak CPU/MPS uyumlu PyTorch fallback'ine döner.
102
+ Her iki yol da autograd desteklidir.
103
+
104
+ ### Katmanlar
105
+
106
+ ```python
107
+ import torch
108
+ from raglu import RaGLU, RaLU
109
+
110
+ # Girdiyi 2 * out_features boyutuna genişletip gate/val olarak böler.
111
+ layer = RaGLU(in_features=768, out_features=768)
112
+ x = torch.randn(8, 128, 768)
113
+ y = layer(x) # (8, 128, 768)
114
+
115
+ # Kapısız aktivasyon
116
+ act = RaLU()
117
+ z = act(x) # (8, 128, 768)
118
+ ```
119
+
120
+ Hazır `gate` ve `val` modülleri de kullanılabilir:
121
+
122
+ ```python
123
+ from torch import nn
124
+ from raglu import RaGLU
125
+
126
+ layer = RaGLU(
127
+ gate=nn.Linear(768, 1024),
128
+ val=nn.Linear(768, 1024),
129
+ )
130
+ ```
131
+
132
+ ### Apple MLX
133
+
134
+ ```python
135
+ import mlx.core as mx
136
+ from raglu import mlx_pure_rational_glu, mlx_pure_rational
137
+
138
+ gate = mx.random.normal((32, 128))
139
+ val = mx.random.normal((32, 128))
140
+
141
+ y = mlx_pure_rational_glu(gate, val)
142
+ z = mlx_pure_rational(gate)
143
+ ```
144
+
145
+ MLX kurulu değilse bu semboller dışa aktarılmaz; `raglu.HAS_MLX` ile kontrol
146
+ edebilirsiniz.
147
+
148
+ ## API
149
+
150
+ | Sembol | Açıklama |
151
+ | --- | --- |
152
+ | `raglu.fused_pure_rational_glu(gate, val)` | Kapılı Pure Rational GLU (Triton/CUDA veya PyTorch fallback) |
153
+ | `raglu.fused_pure_rational(x)` | Kapısız RaLU aktivasyonu |
154
+ | `raglu.RaGLU` | Doğrusal katman + Pure Rational GLU `nn.Module`'ü |
155
+ | `raglu.RaLU` | Element-wise RaLU `nn.Module`'ü |
156
+ | `raglu.mlx_pure_rational_glu` | MLX kapılı varyant (MLX varsa) |
157
+ | `raglu.mlx_pure_rational` | MLX kapısız varyant (MLX varsa) |
158
+ | `raglu.HAS_TRITON` | Triton çekirdeklerinin kullanılabilirliği |
159
+ | `raglu.HAS_MLX` | MLX'in kullanılabilirliği |
160
+
161
+ ### Not: CUDA clamp
162
+
163
+ Triton çekirdekleri sayısal kararlılık için kapı değerini `[-50, 50]` aralığına
164
+ kırpar. Bu aralığın dışındaki değerlerde Triton ve fallback çıktıları
165
+ farklılaşabilir; pratik aktivasyon girdilerinde fark yoktur.
166
+
167
+ ## Geliştirme
168
+
169
+ ```bash
170
+ git clone <repo-url>
171
+ cd RaGLU
172
+ python -m venv .venv
173
+ source .venv/bin/activate
174
+ pip install -e ".[dev]"
175
+ pytest -v
176
+ ```
177
+
178
+ Triton testleri yalnızca CUDA + Triton mevcut olduğunda, MLX testleri ise
179
+ yalnızca MLX kurulu olduğunda çalışır; diğer ortamlarda otomatik atlanır.
180
+
181
+ ### Paket derleme
182
+
183
+ ```bash
184
+ python -m build
185
+ python -m twine check dist/*
186
+ ```
187
+
188
+ ## Lisans
189
+
190
+ MIT — bkz. [LICENSE](LICENSE).
191
+
192
+ Copyright (c) 2026 Ömer Faruk Solmaz
raglu-0.1.0/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # RaGLU
2
+
3
+ **Pure Rational GLU (RaGLU)** ve **RaLU** aktivasyon fonksiyonları için platform
4
+ bağımsız PyTorch kütüphanesi. NVIDIA CUDA'da isteğe bağlı **Triton** çekirdekleri,
5
+ Apple Silicon'da ise yerel **MLX** desteği sunar.
6
+
7
+ Paket iki `nn.Module` sınıfı sunar:
8
+
9
+ | Sınıf | Görevi |
10
+ | --- | --- |
11
+ | `RaGLU()` | Kapılı (GLU) katman: `Linear` çıktısını gate/val olarak ikiye böler, `f(g) * v` uygular. |
12
+ | `RaLU()` | Kapısız, element-wise aktivasyon: `f(x)` uygular, şekli değiştirmez. |
13
+
14
+ ## Fonksiyonlar
15
+
16
+ Kapılı (gated) varyant:
17
+
18
+ $$
19
+ \operatorname{RaGLU}(g, v) = \frac{g^3 + g}{g^2 + 3} \cdot v
20
+ $$
21
+
22
+ Kapısız varyant:
23
+
24
+ $$
25
+ \operatorname{RaLU}(x) = \frac{x^3 + x}{x^2 + 3}
26
+ $$
27
+
28
+ Türev (her iki varyantın çekirdeği):
29
+
30
+ $$
31
+ \frac{d}{dx}\left(\frac{x^3 + x}{x^2 + 3}\right)
32
+ = \frac{x^4 + 8x^2 + 3}{(x^2 + 3)^2}
33
+ $$
34
+
35
+ Fonksiyon tek (odd) bir fonksiyondur: `f(-x) = -f(x)`. Payda her zaman
36
+ `>= 3` olduğundan sayısal olarak kararlıdır.
37
+
38
+ ## Kurulum
39
+
40
+ ```bash
41
+ pip install raglu
42
+ ```
43
+
44
+ İsteğe bağlı hızlandırıcılar:
45
+
46
+ ```bash
47
+ pip install "raglu[triton]" # NVIDIA CUDA için Triton çekirdekleri
48
+ pip install "raglu[mlx]" # Apple Silicon için MLX
49
+ pip install "raglu[dev]" # test + derleme araçları
50
+ ```
51
+
52
+ ## Kullanım
53
+
54
+ ### Fonksiyonel PyTorch API
55
+
56
+ ```python
57
+ import torch
58
+ from raglu import fused_pure_rational_glu, fused_pure_rational
59
+
60
+ gate = torch.randn(32, 128)
61
+ val = torch.randn(32, 128)
62
+
63
+ y = fused_pure_rational_glu(gate, val) # (32, 128)
64
+ z = fused_pure_rational(gate) # (32, 128)
65
+ ```
66
+
67
+ `fused_pure_rational_glu`, CUDA + Triton mevcutsa füzyonlu çekirdeği kullanır.
68
+ Aksi halde otomatik olarak CPU/MPS uyumlu PyTorch fallback'ine döner.
69
+ Her iki yol da autograd desteklidir.
70
+
71
+ ### Katmanlar
72
+
73
+ ```python
74
+ import torch
75
+ from raglu import RaGLU, RaLU
76
+
77
+ # Girdiyi 2 * out_features boyutuna genişletip gate/val olarak böler.
78
+ layer = RaGLU(in_features=768, out_features=768)
79
+ x = torch.randn(8, 128, 768)
80
+ y = layer(x) # (8, 128, 768)
81
+
82
+ # Kapısız aktivasyon
83
+ act = RaLU()
84
+ z = act(x) # (8, 128, 768)
85
+ ```
86
+
87
+ Hazır `gate` ve `val` modülleri de kullanılabilir:
88
+
89
+ ```python
90
+ from torch import nn
91
+ from raglu import RaGLU
92
+
93
+ layer = RaGLU(
94
+ gate=nn.Linear(768, 1024),
95
+ val=nn.Linear(768, 1024),
96
+ )
97
+ ```
98
+
99
+ ### Apple MLX
100
+
101
+ ```python
102
+ import mlx.core as mx
103
+ from raglu import mlx_pure_rational_glu, mlx_pure_rational
104
+
105
+ gate = mx.random.normal((32, 128))
106
+ val = mx.random.normal((32, 128))
107
+
108
+ y = mlx_pure_rational_glu(gate, val)
109
+ z = mlx_pure_rational(gate)
110
+ ```
111
+
112
+ MLX kurulu değilse bu semboller dışa aktarılmaz; `raglu.HAS_MLX` ile kontrol
113
+ edebilirsiniz.
114
+
115
+ ## API
116
+
117
+ | Sembol | Açıklama |
118
+ | --- | --- |
119
+ | `raglu.fused_pure_rational_glu(gate, val)` | Kapılı Pure Rational GLU (Triton/CUDA veya PyTorch fallback) |
120
+ | `raglu.fused_pure_rational(x)` | Kapısız RaLU aktivasyonu |
121
+ | `raglu.RaGLU` | Doğrusal katman + Pure Rational GLU `nn.Module`'ü |
122
+ | `raglu.RaLU` | Element-wise RaLU `nn.Module`'ü |
123
+ | `raglu.mlx_pure_rational_glu` | MLX kapılı varyant (MLX varsa) |
124
+ | `raglu.mlx_pure_rational` | MLX kapısız varyant (MLX varsa) |
125
+ | `raglu.HAS_TRITON` | Triton çekirdeklerinin kullanılabilirliği |
126
+ | `raglu.HAS_MLX` | MLX'in kullanılabilirliği |
127
+
128
+ ### Not: CUDA clamp
129
+
130
+ Triton çekirdekleri sayısal kararlılık için kapı değerini `[-50, 50]` aralığına
131
+ kırpar. Bu aralığın dışındaki değerlerde Triton ve fallback çıktıları
132
+ farklılaşabilir; pratik aktivasyon girdilerinde fark yoktur.
133
+
134
+ ## Geliştirme
135
+
136
+ ```bash
137
+ git clone <repo-url>
138
+ cd RaGLU
139
+ python -m venv .venv
140
+ source .venv/bin/activate
141
+ pip install -e ".[dev]"
142
+ pytest -v
143
+ ```
144
+
145
+ Triton testleri yalnızca CUDA + Triton mevcut olduğunda, MLX testleri ise
146
+ yalnızca MLX kurulu olduğunda çalışır; diğer ortamlarda otomatik atlanır.
147
+
148
+ ### Paket derleme
149
+
150
+ ```bash
151
+ python -m build
152
+ python -m twine check dist/*
153
+ ```
154
+
155
+ ## Lisans
156
+
157
+ MIT — bkz. [LICENSE](LICENSE).
158
+
159
+ Copyright (c) 2026 Ömer Faruk Solmaz
@@ -0,0 +1,61 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "raglu"
7
+ version = "0.1.0"
8
+ description = "Pure Rational GLU (RaGLU) and RaLU activations for PyTorch, Triton CUDA and Apple MLX."
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [
14
+ { name = "Ömer Faruk Solmaz" },
15
+ ]
16
+ keywords = [
17
+ "activation",
18
+ "glu",
19
+ "ralu",
20
+ "rational",
21
+ "pytorch",
22
+ "triton",
23
+ "mlx",
24
+ "deep-learning",
25
+ ]
26
+ classifiers = [
27
+ "Development Status :: 4 - Beta",
28
+ "Intended Audience :: Developers",
29
+ "Intended Audience :: Science/Research",
30
+ "Programming Language :: Python :: 3",
31
+ "Programming Language :: Python :: 3 :: Only",
32
+ "Programming Language :: Python :: 3.9",
33
+ "Programming Language :: Python :: 3.10",
34
+ "Programming Language :: Python :: 3.11",
35
+ "Programming Language :: Python :: 3.12",
36
+ "Programming Language :: Python :: 3.13",
37
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
38
+ "Typing :: Typed",
39
+ ]
40
+ dependencies = [
41
+ "torch>=2.0.0",
42
+ ]
43
+
44
+ [project.optional-dependencies]
45
+ triton = ["triton>=2.0.0"]
46
+ mlx = ["mlx>=0.1.0"]
47
+ dev = [
48
+ "pytest>=7.0.0",
49
+ "build>=1.0.0",
50
+ "twine>=4.0.0",
51
+ ]
52
+
53
+ [tool.setuptools.packages.find]
54
+ include = ["raglu*"]
55
+
56
+ [tool.setuptools.package-data]
57
+ raglu = ["py.typed"]
58
+
59
+ [tool.pytest.ini_options]
60
+ testpaths = ["tests"]
61
+ addopts = "-ra"
@@ -0,0 +1,31 @@
1
+ """RaGLU: Pure Rational GLU ve RaLU aktivasyonları.
2
+
3
+ PyTorch (CPU/CUDA/MPS), isteğe bağlı Triton CUDA çekirdekleri ve Apple MLX
4
+ desteği sunar.
5
+ """
6
+
7
+ from .core import (
8
+ HAS_MLX,
9
+ HAS_TRITON,
10
+ fused_pure_rational,
11
+ fused_pure_rational_glu,
12
+ )
13
+ from .torch_module import RaGLU, RaLU
14
+
15
+ if HAS_MLX:
16
+ from .core import mlx_pure_rational, mlx_pure_rational_glu
17
+
18
+ __version__ = "0.1.0"
19
+
20
+ __all__ = [
21
+ "fused_pure_rational_glu",
22
+ "fused_pure_rational",
23
+ "RaGLU",
24
+ "RaLU",
25
+ "HAS_TRITON",
26
+ "HAS_MLX",
27
+ "__version__",
28
+ ]
29
+
30
+ if HAS_MLX:
31
+ __all__ += ["mlx_pure_rational_glu", "mlx_pure_rational"]
@@ -0,0 +1,116 @@
1
+ import torch
2
+
3
+ # Triton ve CUDA kontrolü
4
+ HAS_TRITON = False
5
+ if torch.cuda.is_available():
6
+ try:
7
+ import triton
8
+ import triton.language as tl
9
+ HAS_TRITON = True
10
+ except ImportError:
11
+ HAS_TRITON = False
12
+
13
+ # MLX kontrolü (Apple Silicon / Mac desteği için)
14
+ HAS_MLX = False
15
+ try:
16
+ import mlx.core as mx
17
+ import mlx.nn as mx_nn
18
+ HAS_MLX = True
19
+ except ImportError:
20
+ HAS_MLX = False
21
+
22
+
23
+ # ==============================================================================
24
+ # 1. TRITON KERNELS (NVIDIA CUDA OPTİMİZE)
25
+ # ==============================================================================
26
+ if HAS_TRITON:
27
+ @triton.jit
28
+ def _pure_rational_glu_fwd_kernel(gate_ptr, val_ptr, out_ptr, n_elements, BLOCK_SIZE: tl.constexpr):
29
+ pid = tl.program_id(axis=0)
30
+ offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
31
+ mask = offsets < n_elements
32
+
33
+ g = tl.load(gate_ptr + offsets, mask=mask)
34
+ v = tl.load(val_ptr + offsets, mask=mask)
35
+
36
+ g = tl.clamp(g, -50.0, 50.0)
37
+ g_sq = g * g
38
+ fg = (g * g_sq + g) / (g_sq + 3.0)
39
+ tl.store(out_ptr + offsets, fg * v, mask=mask)
40
+
41
+ @triton.jit
42
+ def _pure_rational_glu_bwd_kernel(dy_ptr, gate_ptr, val_ptr, dg_ptr, dv_ptr, n_elements, BLOCK_SIZE: tl.constexpr):
43
+ pid = tl.program_id(axis=0)
44
+ offsets = pid * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
45
+ mask = offsets < n_elements
46
+
47
+ dy = tl.load(dy_ptr + offsets, mask=mask)
48
+ g = tl.load(gate_ptr + offsets, mask=mask)
49
+ v = tl.load(val_ptr + offsets, mask=mask)
50
+
51
+ g = tl.clamp(g, -50.0, 50.0)
52
+ g_sq = g * g
53
+ denom = g_sq + 3.0
54
+
55
+ fg = (g * g_sq + g) / denom
56
+ dv = dy * fg
57
+ dfg = (g_sq * g_sq + 8.0 * g_sq + 3.0) / (denom * denom)
58
+ dg = dy * v * dfg
59
+
60
+ tl.store(dv_ptr + offsets, dv, mask=mask)
61
+ tl.store(dg_ptr + offsets, dg, mask=mask)
62
+
63
+ class FusedPureRationalGLUFunction(torch.autograd.Function):
64
+ @staticmethod
65
+ def forward(ctx, gate, val):
66
+ gate_c, val_c = gate.contiguous(), val.contiguous()
67
+ n_elements = gate_c.numel()
68
+ out = torch.empty_like(gate_c)
69
+ GRID = lambda meta: (triton.cdiv(n_elements, meta['BLOCK_SIZE']),)
70
+ _pure_rational_glu_fwd_kernel[GRID](gate_c, val_c, out, n_elements, BLOCK_SIZE=1024)
71
+ ctx.save_for_backward(gate_c, val_c)
72
+ return out
73
+
74
+ @staticmethod
75
+ def backward(ctx, dy):
76
+ gate, val = ctx.saved_tensors
77
+ dy_c = dy.contiguous()
78
+ n_elements = gate.numel()
79
+ dgate, dval = torch.empty_like(gate), torch.empty_like(val)
80
+ GRID = lambda meta: (triton.cdiv(n_elements, meta['BLOCK_SIZE']),)
81
+ _pure_rational_glu_bwd_kernel[GRID](dy_c, gate, val, dgate, dval, n_elements, BLOCK_SIZE=1024)
82
+ return dgate, dval
83
+
84
+
85
+ # ==============================================================================
86
+ # 2. PYTORCH API (CUDA + MPS/Mac + CPU FALLBACK)
87
+ # ==============================================================================
88
+ def fused_pure_rational_glu(gate: torch.Tensor, val: torch.Tensor) -> torch.Tensor:
89
+ """Pure Rational GLU Function: f(g) = (g^3 + g) / (g^2 + 3) * v"""
90
+ if HAS_TRITON and gate.is_cuda:
91
+ return FusedPureRationalGLUFunction.apply(gate, val)
92
+ else:
93
+ # PyTorch Native Fallback (MPS, CPU veya Triton bulunmayan ortamlar)
94
+ g_sq = gate * gate
95
+ fg = (gate * g_sq + gate) / (g_sq + 3.0)
96
+ return fg * val
97
+
98
+
99
+ def fused_pure_rational(x: torch.Tensor) -> torch.Tensor:
100
+ """RaLU (Non-GLU Pure Rational): f(x) = (x^3 + x) / (x^2 + 3)"""
101
+ x_sq = x * x
102
+ return (x * x_sq + x) / (x_sq + 3.0)
103
+
104
+
105
+ # ==============================================================================
106
+ # 3. APPLE MLX NATIVE DESTEĞİ
107
+ # ==============================================================================
108
+ if HAS_MLX:
109
+ def mlx_pure_rational_glu(gate: mx.array, val: mx.array) -> mx.array:
110
+ g_sq = mx.square(gate)
111
+ fg = (gate * g_sq + gate) / (g_sq + 3.0)
112
+ return fg * val
113
+
114
+ def mlx_pure_rational(x: mx.array) -> mx.array:
115
+ x_sq = mx.square(x)
116
+ return (x * x_sq + x) / (x_sq + 3.0)
File without changes
@@ -0,0 +1,121 @@
1
+ """PyTorch ``nn.Module`` katman sarmalayıcıları.
2
+
3
+ ``RaGLU`` gated (kapılı) doğrusal katmanı, ``RaLU`` ise kapısız
4
+ element-wise aktivasyonu sağlar.
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from torch import Tensor, nn
10
+
11
+ from .core import fused_pure_rational, fused_pure_rational_glu
12
+
13
+ __all__ = ["RaGLU", "RaLU"]
14
+
15
+
16
+ class RaGLU(nn.Module):
17
+ """Pure Rational GLU katmanı.
18
+
19
+ İki kullanım biçimi vardır:
20
+
21
+ 1. Yerleşik doğrusal katman (önerilen)::
22
+
23
+ layer = RaGLU(in_features=768, out_features=768)
24
+ y = layer(x) # x: (..., 768) -> y: (..., 768)
25
+
26
+ Girdi, tek bir doğrusal katmanla ``2 * out_features`` boyutuna
27
+ genişletilir ve ikiye bölünür. İlk yarı kapı (``gate``), ikinci yarı
28
+ değer (``val``) olarak kullanılır.
29
+
30
+ 2. Hazır ``gate`` ve ``val`` modülleri ile::
31
+
32
+ layer = RaGLU(gate=nn.Linear(768, 1024), val=nn.Linear(768, 1024))
33
+ y = layer(x)
34
+
35
+ Args:
36
+ in_features: Girdi özellik sayısı (yerleşik modda zorunludur).
37
+ out_features: Çıktı özellik sayısı. Varsayılan olarak ``in_features``.
38
+ bias: Yerleşik doğrusal katmanda bias kullanılıp kullanılmayacağı.
39
+ gate: Hazır kapı modülü. Verilirse ``val`` da verilmelidir.
40
+ val: Hazır değer modülü. Verilirse ``gate`` de verilmelidir.
41
+
42
+ Girdi ve çıktı şekilleri aynı son boyuta sahip olmalıdır: ``gate`` ve
43
+ ``val`` çıktıları eşleşmezse hata verilir.
44
+ """
45
+
46
+ def __init__(
47
+ self,
48
+ in_features: int | None = None,
49
+ out_features: int | None = None,
50
+ bias: bool = True,
51
+ gate: nn.Module | None = None,
52
+ val: nn.Module | None = None,
53
+ ) -> None:
54
+ super().__init__()
55
+
56
+ self.in_features: int | None = in_features
57
+ self.out_features: int | None = out_features
58
+
59
+ if gate is not None or val is not None:
60
+ if gate is None or val is None:
61
+ raise ValueError("'gate' ve 'val' birlikte verilmelidir.")
62
+ if in_features is not None or out_features is not None:
63
+ raise ValueError(
64
+ "Hazır 'gate'/'val' modülleriyle 'in_features'/'out_features' birlikte kullanılamaz."
65
+ )
66
+ self.linear = None
67
+ self.gate = gate
68
+ self.val = val
69
+ else:
70
+ if in_features is None:
71
+ raise ValueError("'in_features' veya hem 'gate' hem 'val' verilmelidir.")
72
+ if out_features is None:
73
+ out_features = in_features
74
+ self.in_features = in_features
75
+ self.out_features = out_features
76
+
77
+ # Tek matmul ile gate ve val üretimi (GLU standardı).
78
+ self.linear: nn.Linear | None = nn.Linear(
79
+ in_features, 2 * out_features, bias=bias
80
+ )
81
+ self.gate = None
82
+ self.val = None
83
+
84
+ def forward(self, x: Tensor) -> Tensor:
85
+ """``x`` üzerinde Pure Rational GLU uygular."""
86
+ if self.linear is not None:
87
+ gate, val = self.linear(x).chunk(2, dim=-1)
88
+ else:
89
+ gate = self.gate(x)
90
+ val = self.val(x)
91
+ if gate.shape != val.shape:
92
+ raise ValueError(
93
+ f"'gate' ve 'val' çıktı şekilleri eşleşmiyor: "
94
+ f"{tuple(gate.shape)} != {tuple(val.shape)}"
95
+ )
96
+
97
+ return fused_pure_rational_glu(gate, val)
98
+
99
+ def extra_repr(self) -> str:
100
+ if self.linear is not None:
101
+ return (
102
+ f"in_features={self.in_features}, out_features={self.out_features}, "
103
+ f"bias={self.linear.bias is not None}"
104
+ )
105
+ return "gate=<custom>, val=<custom>"
106
+
107
+
108
+ class RaLU(nn.Module):
109
+ """Kapısız Pure Rational aktivasyonu.
110
+
111
+ ``f(x) = (x^3 + x) / (x^2 + 3)``
112
+
113
+ Şekil değiştirmez; tüm tensörlerde (``float16``/``bfloat16``/``float32``)
114
+ ve cihazlarda (CPU/CUDA/MPS) çalışır.
115
+ """
116
+
117
+ def forward(self, x: Tensor) -> Tensor:
118
+ return fused_pure_rational(x)
119
+
120
+ def extra_repr(self) -> str:
121
+ return "inplace=False"
@@ -0,0 +1,192 @@
1
+ Metadata-Version: 2.4
2
+ Name: raglu
3
+ Version: 0.1.0
4
+ Summary: Pure Rational GLU (RaGLU) and RaLU activations for PyTorch, Triton CUDA and Apple MLX.
5
+ Author: Ömer Faruk Solmaz
6
+ License-Expression: MIT
7
+ Keywords: activation,glu,ralu,rational,pytorch,triton,mlx,deep-learning
8
+ Classifier: Development Status :: 4 - Beta
9
+ Classifier: Intended Audience :: Developers
10
+ Classifier: Intended Audience :: Science/Research
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.9
14
+ Classifier: Programming Language :: Python :: 3.10
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.9
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: torch>=2.0.0
24
+ Provides-Extra: triton
25
+ Requires-Dist: triton>=2.0.0; extra == "triton"
26
+ Provides-Extra: mlx
27
+ Requires-Dist: mlx>=0.1.0; extra == "mlx"
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
30
+ Requires-Dist: build>=1.0.0; extra == "dev"
31
+ Requires-Dist: twine>=4.0.0; extra == "dev"
32
+ Dynamic: license-file
33
+
34
+ # RaGLU
35
+
36
+ **Pure Rational GLU (RaGLU)** ve **RaLU** aktivasyon fonksiyonları için platform
37
+ bağımsız PyTorch kütüphanesi. NVIDIA CUDA'da isteğe bağlı **Triton** çekirdekleri,
38
+ Apple Silicon'da ise yerel **MLX** desteği sunar.
39
+
40
+ Paket iki `nn.Module` sınıfı sunar:
41
+
42
+ | Sınıf | Görevi |
43
+ | --- | --- |
44
+ | `RaGLU()` | Kapılı (GLU) katman: `Linear` çıktısını gate/val olarak ikiye böler, `f(g) * v` uygular. |
45
+ | `RaLU()` | Kapısız, element-wise aktivasyon: `f(x)` uygular, şekli değiştirmez. |
46
+
47
+ ## Fonksiyonlar
48
+
49
+ Kapılı (gated) varyant:
50
+
51
+ $$
52
+ \operatorname{RaGLU}(g, v) = \frac{g^3 + g}{g^2 + 3} \cdot v
53
+ $$
54
+
55
+ Kapısız varyant:
56
+
57
+ $$
58
+ \operatorname{RaLU}(x) = \frac{x^3 + x}{x^2 + 3}
59
+ $$
60
+
61
+ Türev (her iki varyantın çekirdeği):
62
+
63
+ $$
64
+ \frac{d}{dx}\left(\frac{x^3 + x}{x^2 + 3}\right)
65
+ = \frac{x^4 + 8x^2 + 3}{(x^2 + 3)^2}
66
+ $$
67
+
68
+ Fonksiyon tek (odd) bir fonksiyondur: `f(-x) = -f(x)`. Payda her zaman
69
+ `>= 3` olduğundan sayısal olarak kararlıdır.
70
+
71
+ ## Kurulum
72
+
73
+ ```bash
74
+ pip install raglu
75
+ ```
76
+
77
+ İsteğe bağlı hızlandırıcılar:
78
+
79
+ ```bash
80
+ pip install "raglu[triton]" # NVIDIA CUDA için Triton çekirdekleri
81
+ pip install "raglu[mlx]" # Apple Silicon için MLX
82
+ pip install "raglu[dev]" # test + derleme araçları
83
+ ```
84
+
85
+ ## Kullanım
86
+
87
+ ### Fonksiyonel PyTorch API
88
+
89
+ ```python
90
+ import torch
91
+ from raglu import fused_pure_rational_glu, fused_pure_rational
92
+
93
+ gate = torch.randn(32, 128)
94
+ val = torch.randn(32, 128)
95
+
96
+ y = fused_pure_rational_glu(gate, val) # (32, 128)
97
+ z = fused_pure_rational(gate) # (32, 128)
98
+ ```
99
+
100
+ `fused_pure_rational_glu`, CUDA + Triton mevcutsa füzyonlu çekirdeği kullanır.
101
+ Aksi halde otomatik olarak CPU/MPS uyumlu PyTorch fallback'ine döner.
102
+ Her iki yol da autograd desteklidir.
103
+
104
+ ### Katmanlar
105
+
106
+ ```python
107
+ import torch
108
+ from raglu import RaGLU, RaLU
109
+
110
+ # Girdiyi 2 * out_features boyutuna genişletip gate/val olarak böler.
111
+ layer = RaGLU(in_features=768, out_features=768)
112
+ x = torch.randn(8, 128, 768)
113
+ y = layer(x) # (8, 128, 768)
114
+
115
+ # Kapısız aktivasyon
116
+ act = RaLU()
117
+ z = act(x) # (8, 128, 768)
118
+ ```
119
+
120
+ Hazır `gate` ve `val` modülleri de kullanılabilir:
121
+
122
+ ```python
123
+ from torch import nn
124
+ from raglu import RaGLU
125
+
126
+ layer = RaGLU(
127
+ gate=nn.Linear(768, 1024),
128
+ val=nn.Linear(768, 1024),
129
+ )
130
+ ```
131
+
132
+ ### Apple MLX
133
+
134
+ ```python
135
+ import mlx.core as mx
136
+ from raglu import mlx_pure_rational_glu, mlx_pure_rational
137
+
138
+ gate = mx.random.normal((32, 128))
139
+ val = mx.random.normal((32, 128))
140
+
141
+ y = mlx_pure_rational_glu(gate, val)
142
+ z = mlx_pure_rational(gate)
143
+ ```
144
+
145
+ MLX kurulu değilse bu semboller dışa aktarılmaz; `raglu.HAS_MLX` ile kontrol
146
+ edebilirsiniz.
147
+
148
+ ## API
149
+
150
+ | Sembol | Açıklama |
151
+ | --- | --- |
152
+ | `raglu.fused_pure_rational_glu(gate, val)` | Kapılı Pure Rational GLU (Triton/CUDA veya PyTorch fallback) |
153
+ | `raglu.fused_pure_rational(x)` | Kapısız RaLU aktivasyonu |
154
+ | `raglu.RaGLU` | Doğrusal katman + Pure Rational GLU `nn.Module`'ü |
155
+ | `raglu.RaLU` | Element-wise RaLU `nn.Module`'ü |
156
+ | `raglu.mlx_pure_rational_glu` | MLX kapılı varyant (MLX varsa) |
157
+ | `raglu.mlx_pure_rational` | MLX kapısız varyant (MLX varsa) |
158
+ | `raglu.HAS_TRITON` | Triton çekirdeklerinin kullanılabilirliği |
159
+ | `raglu.HAS_MLX` | MLX'in kullanılabilirliği |
160
+
161
+ ### Not: CUDA clamp
162
+
163
+ Triton çekirdekleri sayısal kararlılık için kapı değerini `[-50, 50]` aralığına
164
+ kırpar. Bu aralığın dışındaki değerlerde Triton ve fallback çıktıları
165
+ farklılaşabilir; pratik aktivasyon girdilerinde fark yoktur.
166
+
167
+ ## Geliştirme
168
+
169
+ ```bash
170
+ git clone <repo-url>
171
+ cd RaGLU
172
+ python -m venv .venv
173
+ source .venv/bin/activate
174
+ pip install -e ".[dev]"
175
+ pytest -v
176
+ ```
177
+
178
+ Triton testleri yalnızca CUDA + Triton mevcut olduğunda, MLX testleri ise
179
+ yalnızca MLX kurulu olduğunda çalışır; diğer ortamlarda otomatik atlanır.
180
+
181
+ ### Paket derleme
182
+
183
+ ```bash
184
+ python -m build
185
+ python -m twine check dist/*
186
+ ```
187
+
188
+ ## Lisans
189
+
190
+ MIT — bkz. [LICENSE](LICENSE).
191
+
192
+ Copyright (c) 2026 Ömer Faruk Solmaz
@@ -0,0 +1,13 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ raglu/__init__.py
5
+ raglu/core.py
6
+ raglu/py.typed
7
+ raglu/torch_module.py
8
+ raglu.egg-info/PKG-INFO
9
+ raglu.egg-info/SOURCES.txt
10
+ raglu.egg-info/dependency_links.txt
11
+ raglu.egg-info/requires.txt
12
+ raglu.egg-info/top_level.txt
13
+ tests/test_raglu.py
@@ -0,0 +1,12 @@
1
+ torch>=2.0.0
2
+
3
+ [dev]
4
+ pytest>=7.0.0
5
+ build>=1.0.0
6
+ twine>=4.0.0
7
+
8
+ [mlx]
9
+ mlx>=0.1.0
10
+
11
+ [triton]
12
+ triton>=2.0.0
@@ -0,0 +1 @@
1
+ raglu
raglu-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,289 @@
1
+ """RaGLU testleri: PyTorch autograd, Triton ve MLX doğrulaması."""
2
+
3
+ import math
4
+
5
+ import pytest
6
+ import torch
7
+
8
+ import raglu
9
+ from raglu import (
10
+ HAS_MLX,
11
+ HAS_TRITON,
12
+ RaGLU,
13
+ RaLU,
14
+ fused_pure_rational,
15
+ fused_pure_rational_glu,
16
+ )
17
+
18
+
19
+ def _reference_rational(x: torch.Tensor) -> torch.Tensor:
20
+ x_sq = x * x
21
+ return (x * x_sq + x) / (x_sq + 3.0)
22
+
23
+
24
+ def _reference_glu(gate: torch.Tensor, val: torch.Tensor) -> torch.Tensor:
25
+ return _reference_rational(gate) * val
26
+
27
+
28
+ # ==============================================================================
29
+ # PyTorch fallback: ileri yön
30
+ # ==============================================================================
31
+ def test_ralu_matches_reference():
32
+ torch.manual_seed(0)
33
+ x = torch.randn(1024, dtype=torch.float64)
34
+ out = fused_pure_rational(x)
35
+ assert torch.allclose(out, _reference_rational(x), atol=1e-12, rtol=1e-12)
36
+
37
+
38
+ def test_raglu_matches_reference():
39
+ torch.manual_seed(0)
40
+ gate = torch.randn(64, 128, dtype=torch.float64)
41
+ val = torch.randn(64, 128, dtype=torch.float64)
42
+ out = fused_pure_rational_glu(gate, val)
43
+ assert torch.allclose(out, _reference_glu(gate, val), atol=1e-12, rtol=1e-12)
44
+
45
+
46
+ @pytest.mark.parametrize("dtype", [torch.float32, torch.float64])
47
+ def test_shapes_and_dtypes_preserved(dtype):
48
+ gate = torch.randn(3, 5, 7, dtype=dtype)
49
+ val = torch.randn(3, 5, 7, dtype=dtype)
50
+ out = fused_pure_rational_glu(gate, val)
51
+ assert out.shape == gate.shape
52
+ assert out.dtype == dtype
53
+
54
+
55
+ @pytest.mark.skipif(not torch.backends.mps.is_available(), reason="MPS yok")
56
+ def test_mps_fallback_forward_backward():
57
+ gate = torch.randn(4, 8, device="mps", requires_grad=True)
58
+ val = torch.randn(4, 8, device="mps", requires_grad=True)
59
+ out = fused_pure_rational_glu(gate, val)
60
+ assert out.device.type == "mps"
61
+ out.sum().backward()
62
+ assert gate.grad is not None and torch.isfinite(gate.grad).all()
63
+ assert val.grad is not None and torch.isfinite(val.grad).all()
64
+
65
+
66
+ def test_odd_and_empty_sizes():
67
+ # Triton çekirdeğinin maskeleme sınırları ve boş tensörler.
68
+ gate = torch.randn(1023, dtype=torch.float64)
69
+ val = torch.randn(1023, dtype=torch.float64)
70
+ assert torch.allclose(
71
+ fused_pure_rational_glu(gate, val), _reference_glu(gate, val), atol=1e-12
72
+ )
73
+
74
+ empty = torch.empty(0, dtype=torch.float64)
75
+ out = fused_pure_rational_glu(empty, empty)
76
+ assert out.shape == (0,)
77
+
78
+
79
+ def test_function_is_odd():
80
+ # f(-x) = -f(x) olduğundan aktivasyon tek fonksiyondur.
81
+ x = torch.linspace(-5.0, 5.0, 101, dtype=torch.float64)
82
+ assert torch.allclose(fused_pure_rational(-x), -fused_pure_rational(x), atol=1e-12)
83
+
84
+
85
+ # ==============================================================================
86
+ # Gradyan doğrulaması (torch.autograd.gradcheck)
87
+ # ==============================================================================
88
+ def test_ralu_gradcheck():
89
+ x = torch.randn(16, 16, dtype=torch.float64, requires_grad=True)
90
+ assert torch.autograd.gradcheck(fused_pure_rational, (x,), eps=1e-6, atol=1e-5)
91
+
92
+
93
+ def test_raglu_gradcheck():
94
+ gate = torch.randn(16, 16, dtype=torch.float64, requires_grad=True)
95
+ val = torch.randn(16, 16, dtype=torch.float64, requires_grad=True)
96
+ assert torch.autograd.gradcheck(
97
+ fused_pure_rational_glu, (gate, val), eps=1e-6, atol=1e-5
98
+ )
99
+
100
+
101
+ def test_raglu_gradcheck_non_contiguous():
102
+ gate = torch.randn(32, 32, dtype=torch.float64, requires_grad=True).t()
103
+ val = torch.randn(32, 32, dtype=torch.float64, requires_grad=True).t()
104
+ assert torch.autograd.gradcheck(
105
+ fused_pure_rational_glu, (gate, val), eps=1e-6, atol=1e-5
106
+ )
107
+
108
+
109
+ def test_raglu_backward_formula():
110
+ x = torch.linspace(-3.0, 3.0, 101, dtype=torch.float64, requires_grad=True)
111
+ fused_pure_rational(x).sum().backward()
112
+ # df/dx = (x^4 + 8x^2 + 3) / (x^2 + 3)^2
113
+ x_sq = x.detach() ** 2
114
+ expected = (x_sq**2 + 8.0 * x_sq + 3.0) / (x_sq + 3.0) ** 2
115
+ assert torch.allclose(x.grad, expected, atol=1e-12, rtol=1e-12)
116
+
117
+
118
+ # ==============================================================================
119
+ # nn.Module katmanları
120
+ # ==============================================================================
121
+ def test_ralu_module_shape_and_grad():
122
+ layer = RaLU()
123
+ x = torch.randn(4, 8, requires_grad=True)
124
+ out = layer(x)
125
+ assert out.shape == x.shape
126
+ out.sum().backward()
127
+ assert x.grad is not None
128
+ assert torch.isfinite(x.grad).all()
129
+
130
+
131
+ def test_raglu_module_default_out_features():
132
+ layer = RaGLU(16)
133
+ x = torch.randn(2, 3, 16)
134
+ out = layer(x)
135
+ assert out.shape == (2, 3, 16)
136
+ assert layer.linear.weight.shape == (32, 16)
137
+ assert "in_features=16" in repr(layer)
138
+
139
+
140
+ def test_raglu_module_projection():
141
+ layer = RaGLU(16, 32, bias=False)
142
+ x = torch.randn(5, 16)
143
+ out = layer(x)
144
+ assert out.shape == (5, 32)
145
+ assert layer.linear.bias is None
146
+ assert sum(p.numel() for p in layer.parameters()) == 2 * 32 * 16
147
+
148
+
149
+ def test_raglu_module_matches_manual_computation():
150
+ torch.manual_seed(0)
151
+ layer = RaGLU(8, 4).double()
152
+ x = torch.randn(6, 8, dtype=torch.float64)
153
+ linear_out = layer.linear(x)
154
+ gate, val = linear_out.chunk(2, dim=-1)
155
+ expected = _reference_glu(gate, val)
156
+ assert torch.allclose(layer(x), expected, atol=1e-12)
157
+
158
+
159
+ def test_raglu_module_custom_gate_val():
160
+ gate = torch.nn.Linear(8, 12, bias=False)
161
+ val = torch.nn.Linear(8, 12, bias=False)
162
+ layer = RaGLU(gate=gate, val=val)
163
+ x = torch.randn(3, 8)
164
+ assert layer(x).shape == (3, 12)
165
+ assert layer.linear is None
166
+
167
+
168
+ def test_raglu_module_gradcheck():
169
+ torch.manual_seed(0)
170
+ layer = RaGLU(4, 3).double()
171
+ x = torch.randn(5, 4, dtype=torch.float64, requires_grad=True)
172
+ assert torch.autograd.gradcheck(lambda t: layer(t), (x,), eps=1e-6, atol=1e-5)
173
+
174
+
175
+ def test_raglu_module_validation():
176
+ with pytest.raises(ValueError):
177
+ RaGLU()
178
+ with pytest.raises(ValueError):
179
+ RaGLU(gate=torch.nn.Linear(4, 4))
180
+ with pytest.raises(ValueError):
181
+ RaGLU(4, gate=torch.nn.Linear(4, 4), val=torch.nn.Linear(4, 4))
182
+
183
+
184
+ def test_raglu_module_mismatched_custom_shapes():
185
+ layer = RaGLU(
186
+ gate=torch.nn.Linear(4, 8, bias=False),
187
+ val=torch.nn.Linear(4, 7, bias=False),
188
+ )
189
+ with pytest.raises(ValueError):
190
+ layer(torch.randn(2, 4))
191
+
192
+
193
+ def test_package_exports():
194
+ assert raglu.__version__ == "0.1.0"
195
+ for name in (
196
+ "fused_pure_rational_glu",
197
+ "fused_pure_rational",
198
+ "RaGLU",
199
+ "RaLU",
200
+ "HAS_TRITON",
201
+ "HAS_MLX",
202
+ ):
203
+ assert hasattr(raglu, name)
204
+
205
+
206
+ # ==============================================================================
207
+ # Triton fused kernel doğrulaması (yalnızca CUDA + Triton varsa)
208
+ # ==============================================================================
209
+ @pytest.mark.skipif(not (HAS_TRITON and torch.cuda.is_available()), reason="CUDA/Triton yok")
210
+ def test_triton_forward_matches_fallback():
211
+ torch.manual_seed(0)
212
+ device = torch.device("cuda")
213
+ # Clamp sınırı olan +/-50'nin oldukça altında değerler kullanılır.
214
+ gate = torch.randn(4096, device=device) * 3.0
215
+ val = torch.randn(4096, device=device)
216
+
217
+ fused = fused_pure_rational_glu(gate, val)
218
+ g_sq = gate * gate
219
+ fallback = ((gate * g_sq + gate) / (g_sq + 3.0)) * val
220
+
221
+ assert torch.allclose(fused, fallback, atol=1e-4, rtol=1e-4)
222
+
223
+
224
+ @pytest.mark.skipif(not (HAS_TRITON and torch.cuda.is_available()), reason="CUDA/Triton yok")
225
+ def test_triton_backward_matches_autograd():
226
+ torch.manual_seed(1)
227
+ device = torch.device("cuda")
228
+ gate_f = (torch.randn(4096, device=device) * 3.0).requires_grad_(True)
229
+ val_f = torch.randn(4096, device=device, requires_grad=True)
230
+ gate_r = gate_f.detach().clone().requires_grad_(True)
231
+ val_r = val_f.detach().clone().requires_grad_(True)
232
+ dy = torch.randn(4096, device=device)
233
+
234
+ # Fused yol
235
+ fused = raglu.core.FusedPureRationalGLUFunction.apply(gate_f, val_f)
236
+ dg_f, dv_f = torch.autograd.grad(fused, (gate_f, val_f), grad_outputs=dy)
237
+
238
+ # Referans yol
239
+ out_r = _reference_glu(gate_r, val_r)
240
+ dg_r, dv_r = torch.autograd.grad(out_r, (gate_r, val_r), grad_outputs=dy)
241
+
242
+ assert torch.allclose(fused.detach(), out_r.detach(), atol=1e-4, rtol=1e-4)
243
+ assert torch.allclose(dg_f, dg_r, atol=1e-4, rtol=1e-4)
244
+ assert torch.allclose(dv_f, dv_r, atol=1e-4, rtol=1e-4)
245
+
246
+
247
+ @pytest.mark.skipif(not (HAS_TRITON and torch.cuda.is_available()), reason="CUDA/Triton yok")
248
+ def test_triton_non_contiguous_inputs():
249
+ torch.manual_seed(2)
250
+ device = torch.device("cuda")
251
+ gate = (torch.randn(64, 64, device=device) * 2.0).t().requires_grad_(True)
252
+ val = torch.randn(64, 64, device=device).t().requires_grad_(True)
253
+ out = fused_pure_rational_glu(gate, val)
254
+ out.sum().backward()
255
+ assert torch.isfinite(gate.grad).all()
256
+ assert torch.isfinite(val.grad).all()
257
+
258
+
259
+ # ==============================================================================
260
+ # MLX doğrulaması (yalnızca MLX kuruluysa)
261
+ # ==============================================================================
262
+ @pytest.mark.skipif(not HAS_MLX, reason="MLX kurulu değil")
263
+ def test_mlx_matches_pytorch():
264
+ import mlx.core as mx
265
+ import numpy as np
266
+
267
+ gate_np = np.random.default_rng(0).standard_normal((32, 32)).astype(np.float32)
268
+ val_np = np.random.default_rng(1).standard_normal((32, 32)).astype(np.float32)
269
+
270
+ mx_out = raglu.mlx_pure_rational_glu(mx.array(gate_np), mx.array(val_np))
271
+ mx_out = np.array(mx_out)
272
+
273
+ pt_out = fused_pure_rational_glu(
274
+ torch.from_numpy(gate_np), torch.from_numpy(val_np)
275
+ ).numpy()
276
+
277
+ assert np.allclose(mx_out, pt_out, atol=1e-5, rtol=1e-5)
278
+
279
+
280
+ @pytest.mark.skipif(not HAS_MLX, reason="MLX kurulu değil")
281
+ def test_mlx_ralu_values():
282
+ import mlx.core as mx
283
+ import numpy as np
284
+
285
+ x_np = np.linspace(-4.0, 4.0, 101, dtype=np.float32)
286
+ mx_out = np.array(raglu.mlx_pure_rational(mx.array(x_np)))
287
+ x_sq = x_np * x_np
288
+ expected = (x_np * x_sq + x_np) / (x_sq + 3.0)
289
+ assert np.allclose(mx_out, expected, atol=1e-6)