tensorplay 0.1.1__py3-none-any.whl

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.
TensorPlay/__init__.py ADDED
@@ -0,0 +1,38 @@
1
+ """
2
+ TensorPlay - 一个用于深度学习验证的工具包
3
+
4
+ 版本: 0.1.1
5
+ 作者: Welog
6
+ 日期: 2025年9月3日
7
+
8
+ 功能特点:
9
+ - 提供多阶自动微分处理能力
10
+ - 提供计算图可视化功能
11
+ - 支持多维度的模型组件管理
12
+ - 支持JSON格式保存和加载
13
+ - 支持模型结构打印
14
+ - 支持钩子调试
15
+ """
16
+ __version__ = "0.1.1"
17
+ __author__ = "Welog"
18
+ __email__ = "2095774200@shu.edu.cn"
19
+ __description__ = "一个用于深度学习验证的工具包"
20
+ __url__ = "https://github.com/bluemoon-o2/TensorPlay"
21
+ __license__ = "MIT"
22
+
23
+
24
+ # =============================================================================
25
+ # 全局接口
26
+ # =============================================================================
27
+ from .core import (config, no_grad, to_data, Tensor, Layer, Operator, Optimizer)
28
+ from .layer import (Dense, BatchNorm, LayerNorm, Conv2D)
29
+ from .module import (Module, Sequential)
30
+ from .optimizer import (SGD, Adam, Momentum, AdamW, Nadam, Lookahead, RMSprop)
31
+ from .operator import (concatenate, load_operator)
32
+ from .func import (mse, sse, nll, cross_entropy, sphere)
33
+ from .initializer import (he_init, xavier_init, uniform_init, my_init)
34
+ from .utils import (plot_dot_graph, accuracy)
35
+ from .data import (DataLoader)
36
+ from .scheduler import (StepLR, MultiStepLR, ExponentialLR, EarlyStopping)
37
+
38
+ load_operator()
TensorPlay/core.py ADDED
@@ -0,0 +1,420 @@
1
+ import warnings
2
+ import contextlib
3
+ import weakref
4
+ import numpy as np
5
+ import TensorPlay as tp
6
+ from typing import List, Union, Tuple, Optional, Any, Callable, Generator
7
+ warnings.filterwarnings("default", category=UserWarning)
8
+
9
+ # =============================================================================
10
+ # Config
11
+ # =============================================================================
12
+ class Config:
13
+ precision = np.float32
14
+ enable_grad = True
15
+ training = True
16
+
17
+
18
+ @contextlib.contextmanager
19
+ def config(name: str, value: bool) -> Generator:
20
+ """配置是否开启梯度计算的上下文管理器"""
21
+ prev_mode = getattr(Config, name)
22
+ setattr(Config, name, value)
23
+ try:
24
+ yield
25
+ finally:
26
+ setattr(Config, name, prev_mode)
27
+
28
+
29
+ def no_grad() -> contextlib._GeneratorContextManager:
30
+ """上下文管理器,禁用梯度计算"""
31
+ return config("enable_grad", False)
32
+
33
+ # =============================================================================
34
+ # Tensor
35
+ # =============================================================================
36
+ def to_data(data: Union[np.ndarray, tuple, list, int, float]) -> np.ndarray:
37
+ """将数据转换为张量要求格式"""
38
+ if isinstance(data, (tuple, list, int, float, Config.precision)):
39
+ return np.array(data, dtype=Config.precision)
40
+ if isinstance(data, np.ndarray):
41
+ return data.astype(Config.precision)
42
+ else:
43
+ raise TypeError(f"Data must be a numpy array, tuple, list, int, or float (not {type(data).__name__})")
44
+
45
+
46
+ class Tensor:
47
+ """张量:(B, H, W, C)"""
48
+
49
+ __add__: Callable[..., 'Tensor']
50
+ __radd__: Callable[..., 'Tensor']
51
+ __sub__: Callable[..., 'Tensor']
52
+ __rsub__: Callable[..., 'Tensor']
53
+ __mul__: Callable[..., 'Tensor']
54
+ __rmul__: Callable[..., 'Tensor']
55
+ __truediv__: Callable[..., 'Tensor']
56
+ __rtruediv__: Callable[..., 'Tensor']
57
+ __pow__: Callable[..., 'Tensor']
58
+ __rpow__: Callable[..., 'Tensor']
59
+ __matmul__: Callable[..., 'Tensor']
60
+ __getitem__: Callable[..., 'Tensor']
61
+ reslice: Callable[..., 'Tensor']
62
+ sum: Callable[..., 'Tensor']
63
+ max: Callable[..., 'Tensor']
64
+ min: Callable[..., 'Tensor']
65
+ exp: Callable[..., 'Tensor']
66
+ log: Callable[..., 'Tensor']
67
+ mean: Callable[..., 'Tensor']
68
+ relu: Callable[..., 'Tensor']
69
+ leaky_relu: Callable[..., 'Tensor']
70
+ gelu: Callable[..., 'Tensor']
71
+ tanh: Callable[..., 'Tensor']
72
+ softmax: Callable[..., 'Tensor']
73
+ log_softmax: Callable[..., 'Tensor']
74
+ sigmoid: Callable[..., 'Tensor']
75
+ reshape: Callable[..., 'Tensor']
76
+ clip: Callable[..., 'Tensor']
77
+ dropout: Callable[..., 'Tensor']
78
+ expand: Callable[..., 'Tensor']
79
+ flatten: Callable[..., 'Tensor']
80
+ transpose: Callable[..., 'Tensor']
81
+ broadcast: Callable[..., 'Tensor']
82
+ rebroadcast: Callable[..., 'Tensor']
83
+
84
+ T: 'Tensor'
85
+
86
+ def __init__(self, data: Union[np.ndarray, list, int, float], op: 'Operator' = None, name: str = None):
87
+ self.data = to_data(data)
88
+ self.grad = None
89
+ self.op = op
90
+ self.name = name
91
+ self.rank = 0
92
+ self.source_module = None # 用于钩子机制
93
+
94
+ def __repr__(self) -> str:
95
+ return f"Tensor({self.data})"
96
+
97
+ @property
98
+ def shape(self) -> Tuple[int, ...]:
99
+ return self.data.shape
100
+
101
+ @property
102
+ def ndim(self) -> int:
103
+ return self.data.ndim
104
+
105
+ @property
106
+ def size(self) -> int:
107
+ return self.data.size
108
+
109
+ @property
110
+ def dtype(self) -> np.dtype:
111
+ return self.data.dtype
112
+
113
+ def clone(self) -> 'Tensor':
114
+ """返回当前张量的副本,确保梯度独立"""
115
+ cloned_tensor = Tensor(self.data, op=self.op)
116
+ if self.grad is not None:
117
+ cloned_tensor.grad = Tensor(self.grad.data.copy())
118
+ return cloned_tensor
119
+
120
+ def detach(self) -> 'Tensor':
121
+ """返回一个不追踪梯度的张量副本"""
122
+ detached = Tensor(self.data)
123
+ return detached
124
+
125
+ def zero_grad(self) -> None:
126
+ """清空梯度"""
127
+ self.grad = None
128
+
129
+ def one_grad(self) -> None:
130
+ """将梯度设为1"""
131
+ self.grad = Tensor(np.ones(self.shape))
132
+
133
+ @classmethod
134
+ def zeros(cls, shape: Union[int, Tuple[int, ...]]) -> 'Tensor':
135
+ """创建一个指定形状的全0张量"""
136
+ return Tensor(np.zeros(shape))
137
+
138
+ def backward(self, clean: bool = True, retain_grad: bool = True, higher_grad: bool = False) -> None:
139
+ """
140
+ 计算子图的反向传播
141
+ :param clean: bool 是否清理计算图
142
+ :param retain_grad: bool 是否保留下游梯度
143
+ :param higher_grad: bool 是否支持多阶梯度
144
+ """
145
+ Operator.state = False
146
+ self.one_grad()
147
+ # 使用集合避免重复处理同一运算符
148
+ op_set = set()
149
+ queue = []
150
+ # 从输出张量开始,收集所有相关运算符
151
+ if self.op is not None:
152
+ queue.append(self.op)
153
+ op_set.add(self.op)
154
+ # 广度优先搜索收集所有相关运算符
155
+ while queue:
156
+ current_op = queue.pop(0) # 取出队首元素
157
+ if current_op.inp is None:
158
+ continue
159
+ # 处理输入为列表或单个张量的情况
160
+ inputs = current_op.inp if isinstance(current_op.inp, list) else [current_op.inp]
161
+ for inp_tensor in inputs:
162
+ # 确保输入是张量且有运算符,排除起始张量
163
+ if isinstance(inp_tensor, Tensor) and inp_tensor.op is not None and inp_tensor.op not in op_set:
164
+ op_set.add(inp_tensor.op)
165
+ queue.append(inp_tensor.op)
166
+ # 按算符深度和计算顺序逆序处理
167
+ op_list = sorted(op_set, key=lambda x: (x.rank, Operator.compute_list.index(x)), reverse=True)
168
+ for op in op_list:
169
+ if op.inp is None:
170
+ continue
171
+ with config('enable_grad', higher_grad):
172
+ grads = op.propagate_grad()
173
+ for i, grad in enumerate(grads):
174
+ if op.inp[i].grad is None:
175
+ op.inp[i].grad = grad
176
+ else:
177
+ op.inp[i].grad = op.inp[i].grad + grad
178
+ if not retain_grad:
179
+ op.out().grad = None
180
+ Operator.state = True
181
+ if clean:
182
+ if higher_grad:
183
+ # 保留反向计算图
184
+ Operator.clean(specific_ops=op_list)
185
+ else:
186
+ Operator.clean()
187
+
188
+ # =============================================================================
189
+ # Operator
190
+ # =============================================================================
191
+ class Operator:
192
+ """算子基类"""
193
+ compute_list: List['Operator'] = [] # 记录计算顺序
194
+ state: bool = True # 是否在前向状态
195
+
196
+ def __init__(self):
197
+ """子类根据需要重写,没有额外参数不写"""
198
+ if Config.enable_grad:
199
+ self.compute_list.append(self)
200
+ self.inp = None # 输入张量
201
+ self.out = None # 输出张量
202
+ self.rank = 0
203
+
204
+ def __repr__(self) -> str:
205
+ return f"Operator.{self.__class__.__name__}"
206
+
207
+ def __call__(self, *args):
208
+ """前向调用接口"""
209
+ inputs = [inp if isinstance(inp, (Tensor, type(None))) else Tensor(inp) for inp in args]
210
+ datas = [inp.data if inp is not None else None for inp in inputs]
211
+ out = self._forward(*datas)
212
+ if Config.enable_grad:
213
+ self.inp = inputs
214
+ self.out = weakref.ref(out)
215
+ self.rank = max([inp.rank for inp in inputs])
216
+ out.op = self
217
+ out.rank = self.rank + 1
218
+ return out
219
+
220
+ def propagate_grad(self) -> Union[Tensor, List[Tensor]]:
221
+ """后向调用接口,集成反向钩子调用"""
222
+ if not Config.enable_grad and self.state:
223
+ warnings.warn('Attention: forward() run with no grad...\n'
224
+ 'If you are not computing higher-gradients, '
225
+ 'please examine your code.', UserWarning, stacklevel=2)
226
+ g = self._backward()
227
+ # 调用反向钩子
228
+ if self.out().source_module is not None:
229
+ module = self.out().source_module
230
+ module._call_backward_hooks(self.out(), self.inp)
231
+ return g
232
+
233
+ def _forward(self, *args: Any) -> Tensor:
234
+ """前向具体运算"""
235
+ raise NotImplementedError
236
+
237
+ def _backward(self) -> Any:
238
+ """后向具体计算"""
239
+ raise NotImplementedError
240
+
241
+ @classmethod
242
+ def clean(cls, specific_ops: Optional[List['Operator']] = None) -> None:
243
+ """清理计算图数据"""
244
+ if specific_ops is not None:
245
+ while specific_ops:
246
+ ops = specific_ops.pop()
247
+ ops.out().op = None
248
+ cls.compute_list.remove(ops)
249
+ else:
250
+ while cls.compute_list:
251
+ ops = cls.compute_list.pop()
252
+ if ops.out() is not None:
253
+ ops.out().op = None
254
+ cls.compute_list.clear()
255
+
256
+ # =============================================================================
257
+ # Layer
258
+ # =============================================================================
259
+ class Layer:
260
+ """
261
+ 基础参数层,实现钩子功能,所有参数层都需要继承此类
262
+ save和load方法自定义格式,必须互认
263
+ """
264
+ layer_list: List['Layer'] = [] # 基础参数层全局记录,兼容最底层实现
265
+
266
+ def __init__(self, *args):
267
+ self._forward_pre_hooks = {}
268
+ self._forward_hooks = {}
269
+ self._backward_hooks = {}
270
+ # 基础参数层只记录Layer类,Module以上不记录
271
+ if isinstance(self, tp.Module):
272
+ return
273
+ Layer.layer_list.append(self)
274
+
275
+ def __repr__(self) -> str:
276
+ prefix = '' if self.__class__.__name__ == 'Layer' else 'Layer.'
277
+ return f"{prefix}{self.__class__.__name__}"
278
+
279
+ def save(self, *args) -> str:
280
+ """
281
+ 保存接口,所有继承了Layer的类需重写此方法
282
+ :return: 自定义格式,与load方法互认
283
+ """
284
+ raise NotImplementedError
285
+
286
+ def load(self, *args) -> None:
287
+ """
288
+ 读取接口,所有继承了Layer的类需重写此方法
289
+ :param args: str 自定义格式,与save方法互认
290
+ """
291
+ raise NotImplementedError
292
+
293
+ def param(self) -> List[Tensor]:
294
+ """
295
+ 参数接口,所有继承了Layer的类需重写此方法
296
+ :return: list[Tensor]
297
+ """
298
+ raise NotImplementedError
299
+
300
+ @classmethod
301
+ def get_params(cls) -> List[Tensor]:
302
+ """
303
+ 返回所有基础参数层参数,兼容优化器的默认设置
304
+ :return: list[Tensor]
305
+ """
306
+ params = []
307
+ for i in Layer.layer_list:
308
+ # Param返回列表
309
+ if i.param() is not None:
310
+ params += i.param()
311
+ return params
312
+
313
+ def register_forward_pre_hook(self, hook: Callable) -> int:
314
+ """注册前向传播前的钩子"""
315
+ handle = id(hook)
316
+ self._forward_pre_hooks[handle] = hook
317
+ return handle
318
+
319
+ def register_forward_hook(self, hook: Callable) -> int:
320
+ """注册前向传播后的钩子"""
321
+ handle = id(hook)
322
+ self._forward_hooks[handle] = hook
323
+ return handle
324
+
325
+ def register_backward_hook(self, hook: Callable) -> int:
326
+ """注册反向传播的钩子"""
327
+ handle = id(hook)
328
+ self._backward_hooks[handle] = hook
329
+ return handle
330
+
331
+ def remove_hook(self, handle: int) -> None:
332
+ """移除指定钩子"""
333
+ for hooks in [self._forward_pre_hooks, self._forward_hooks, self._backward_hooks]:
334
+ if handle in hooks:
335
+ del hooks[handle]
336
+ return
337
+
338
+ def _call_forward_pre_hooks(self, *args: Tensor, **kwargs) -> None:
339
+ """调用前向传播前的钩子"""
340
+ for hook in self._forward_pre_hooks.values():
341
+ hook(self, args, kwargs)
342
+
343
+ def _call_forward_hooks(self, *args: Tensor, **kwargs) -> None:
344
+ """调用前向传播后的钩子"""
345
+ for hook in self._forward_hooks.values():
346
+ hook(self, args, kwargs, self._forward_result)
347
+
348
+ def _call_backward_hooks(self, grad_outputs: Tensor, inputs: Tensor) -> None:
349
+ """调用反向传播的钩子"""
350
+ for hook in self._backward_hooks.values():
351
+ if isinstance(inputs, Tensor):
352
+ hook(self, grad_outputs, inputs)
353
+ elif isinstance(inputs, list):
354
+ for item in inputs:
355
+ if isinstance(item, Tensor):
356
+ hook(self, grad_outputs, [item for item in inputs])
357
+ else:
358
+ raise TypeError(f"input must be a Tensor or list of Tensors, got {type(inputs).__name__}")
359
+
360
+ def __call__(self, *args: Tensor, **kwargs) -> Tensor:
361
+ """调用方法,集成钩子和张量-模块关联"""
362
+ self._call_forward_pre_hooks(*args, **kwargs)
363
+ self._forward_result = self.forward(*args, **kwargs)
364
+ # 记录输出张量的来源模块(用于反向传播时触发钩子)
365
+ if self._backward_hooks:
366
+ if isinstance(self._forward_result, Tensor):
367
+ self._forward_result._source_module = self
368
+ elif isinstance(self._forward_result, list):
369
+ for item in self._forward_result:
370
+ if isinstance(item, Tensor):
371
+ item._source_module = self
372
+ else:
373
+ raise TypeError(f"forward_result must be a Tensor or list, got {type(self._forward_result).__name__}")
374
+ self._call_forward_hooks(*args, **kwargs)
375
+ return self._forward_result
376
+
377
+ def forward(self, *args: Tensor, **kwargs) -> Tensor:
378
+ """前向传播方法,需要子类实现"""
379
+ raise NotImplementedError(f"Module {self.__class__.__name__} has no forward method implemented")
380
+
381
+ # =============================================================================
382
+ # Optimizer
383
+ # =============================================================================
384
+ class Optimizer:
385
+ """优化器类,储存参数需要重写接口函数save()和load()"""
386
+ hooks = [] # 用于存储钩子函数的列表
387
+
388
+ def __init__(self, params=None):
389
+ """
390
+ :param params:list[Tensor,Tensor...] 需要优化的参数的列表,为None时优化所有Layer中的参数
391
+ """
392
+ if params is None:
393
+ self.params = Layer.get_params()
394
+ else:
395
+ self.params = params
396
+
397
+ def step(self):
398
+ """具体优化方法,必须重写"""
399
+ for hook in self.hooks:
400
+ self.params = hook(self.params)
401
+ self._step()
402
+
403
+ def _step(self):
404
+ """具体优化方法,必须重写"""
405
+ raise NotImplementedError
406
+
407
+ def zero_grad(self):
408
+ """使参数的梯度归零"""
409
+ for i in self.params:
410
+ i.zero_grad()
411
+
412
+ def register_hook(self, hook: Callable) -> int:
413
+ """注册钩子函数"""
414
+ self.hooks.append(hook)
415
+ return len(self.hooks) - 1
416
+
417
+ def remove_hook(self, handle: int):
418
+ """移除指定的钩子函数"""
419
+ if handle in self.hooks:
420
+ del self.hooks[handle]
TensorPlay/data.py ADDED
@@ -0,0 +1,72 @@
1
+ from .core import Tensor
2
+ from .operator import concatenate
3
+ import numpy as np
4
+
5
+ # =============================================================================
6
+ # Datasets
7
+ # =============================================================================
8
+ def load_iris():
9
+ """
10
+ 加载鸢尾花数据集
11
+ ================= ==============
12
+ Classes 3
13
+ Samples per class 50
14
+ Samples total 150
15
+ Dimensionality 4
16
+ Features real, positive
17
+ ================= ==============
18
+ """
19
+ from sklearn.datasets import load_iris
20
+ return load_iris()
21
+
22
+ # =============================================================================
23
+ # DataLoader
24
+ # =============================================================================
25
+ class DataLoader:
26
+ """数据加载器,支持批处理、打乱和自定义转换"""
27
+
28
+ def __init__(self, data, batch_size: int = 64, shuffle: bool = True, transform=None):
29
+ """
30
+ :param data: 数据集,格式为[(输入特征, 标签), ...]
31
+ :param batch_size: 批次大小
32
+ :param shuffle: 是否打乱数据集
33
+ :param transform: 数据转换函数,格式为func(input, label) -> (transformed_input, transformed_label)
34
+ """
35
+ self.data = data
36
+ self.batch_size = batch_size
37
+ self.shuffle = shuffle
38
+ self.transform = transform
39
+ self.indices = list(range(len(data)))
40
+ self.cursor = 0 # 当前批次指针
41
+ if shuffle:
42
+ np.random.shuffle(self.indices)
43
+
44
+ def __iter__(self):
45
+ """迭代器初始化"""
46
+ self.cursor = 0
47
+ if self.shuffle:
48
+ np.random.shuffle(self.indices)
49
+ return self
50
+
51
+ def __next__(self):
52
+ """获取下一个批次"""
53
+ if self.cursor >= len(self.data):
54
+ raise StopIteration
55
+ # 计算当前批次索引范围
56
+ end = min(self.cursor + self.batch_size, len(self.data))
57
+ batch_indices = self.indices[self.cursor:end]
58
+ self.cursor = end
59
+
60
+ batch_inputs = []
61
+ batch_labels = []
62
+ for idx in batch_indices:
63
+ x, y = self.data[idx]
64
+ if self.transform:
65
+ x, y = self.transform(x, y)
66
+ batch_inputs.append(Tensor([x]))
67
+ batch_labels.append(Tensor([y]))
68
+ return concatenate(*batch_inputs, axis=0), concatenate(*batch_labels, axis=0)
69
+
70
+ def __len__(self):
71
+ """返回批次数量"""
72
+ return (len(self.data) + self.batch_size - 1) // self.batch_size
TensorPlay/func.py ADDED
@@ -0,0 +1,81 @@
1
+ from .core import Tensor
2
+ from .operator import MeanSquaredError, CrossEntropy
3
+
4
+ # =============================================================================
5
+ # 损失函数
6
+ # =============================================================================
7
+ def mse(out: Tensor, target: Tensor) -> Tensor:
8
+ """均方误差(Mean Squared Error):MSE = (1/n) * sum((a - b)²)"""
9
+ return MeanSquaredError()(out, target)
10
+
11
+
12
+ def cross_entropy(out: Tensor, target: Tensor, axis: int = 1, activation: str = 'softmax') -> Tensor:
13
+ """交叉熵损失函数"""
14
+ return CrossEntropy(axis=axis, activation=activation)(out, target)
15
+
16
+
17
+ def sse(out: Tensor, target: Tensor) -> Tensor:
18
+ """平方误差(Sum of Squared Error):SSE = sum((a - b)²)"""
19
+ if out.shape != target.shape:
20
+ raise ValueError("SSE can only be calculated between tensors of the same shape")
21
+ return ((out - target) ** 2).sum()
22
+
23
+
24
+ def nll(out: Tensor, target: Tensor) -> Tensor:
25
+ """交叉熵误差(Negative Log Likelihood):NLL = -sum(target * log(output))"""
26
+ if out.shape != target.shape:
27
+ raise ValueError("NLL can only be calculated between tensors of the same shape")
28
+ return -(target * out.log()).sum()
29
+
30
+
31
+
32
+ # =============================================================================
33
+ # 优化函数
34
+ # =============================================================================
35
+ def sphere(x, y):
36
+ return x ** 2 + y ** 2
37
+
38
+
39
+ def matyas(x, y):
40
+ return 0.26 * (x ** 2 + y ** 2) - 0.48 * x * y
41
+
42
+
43
+ def goldstein(x, y):
44
+ return (1 + (x + y + 1) ** 2 * (19 - 14 * x + 3 * x ** 2 - 14 * y + 6 * x * y + 3 * y ** 2)) * (
45
+ 30 + (2 * x - 3 * y) ** 2 * (18 - 32 * x + 12 * x ** 2 + 48 * y - 36 * x * y + 27 * y ** 2))
46
+
47
+
48
+ def higher_optimizer(x, epoch, func, verbose=False):
49
+ """
50
+ 基于牛顿法的二阶单变量函数优化器
51
+ :param x: 初始值
52
+ :param epoch: 迭代次数
53
+ :param func: 目标函数
54
+ :param verbose: 是否打印每次迭代的结果
55
+ :return: 优化后的变量和函数值
56
+ """
57
+ for i in range(epoch):
58
+ y = func(x)
59
+ y.name = 'y'
60
+ if verbose:
61
+ print(f"第{i + 1}次迭代: x={x.data}, y={y.data}")
62
+ y.backward(higher_grad=True)
63
+ gx = x.grad
64
+ gx.name = 'gx'
65
+ x.zero_grad()
66
+ gx.backward()
67
+ gx2 = x.grad
68
+ x.zero_grad()
69
+ x.data -= gx.data / gx2.data
70
+ return x, y
71
+
72
+ # =============================================================================
73
+ # 测试函数
74
+ # =============================================================================
75
+ def deriv(func, x: Tensor, eps=1e-4):
76
+ """函数的数值微分计算,测试用"""
77
+ x1 = Tensor(x.data.data + eps)
78
+ x2 = Tensor(x.data.data - eps)
79
+ y1 = func(x1)
80
+ y2 = func(x2)
81
+ return (y1.data.data - y2.data.data) / (2 * eps)
@@ -0,0 +1,26 @@
1
+ from typing import Tuple
2
+ from .core import Tensor, Config
3
+ import numpy as np
4
+
5
+ def my_init(size) -> Tensor:
6
+ """对单个张量初始化权重"""
7
+ std = np.sqrt(2.0 / size)
8
+ return Tensor(np.random.normal(0, std, size))
9
+
10
+
11
+ def xavier_init(inp_size: int, out_size: int) -> Tensor:
12
+ """Xavier初始化 - 适用于tanh/sigmoid等激活函数"""
13
+ std = np.sqrt(2.0 / (inp_size + out_size))
14
+ return Tensor(np.random.normal(0, std, (out_size, inp_size)))
15
+
16
+
17
+ def he_init(shape: Tuple[int, ...]) -> Tensor:
18
+ """He初始化 - 适用于ReLU及其变体激活函数"""
19
+ fan_in = np.prod(shape[:-1])
20
+ std = np.sqrt(2.0 / fan_in)
21
+ return Tensor(np.random.uniform(-std * np.sqrt(3), std * np.sqrt(3), shape).astype(Config.precision))
22
+
23
+
24
+ def uniform_init(size, a=-0.05, b=0.05) -> Tensor:
25
+ """均匀分布初始化 - 适用于线性层"""
26
+ return Tensor(np.random.uniform(a, b, size))