Package: pydynet
PyDyNet：Neuron Network(DNN, CNN, RNN, etc) implementation using Numpy based on Autodiff前作：PyNet: Use NumPy to build neuron network。在那里我们基于求导规则实现了全连接网络。在这里，我们向当今的深度学习框架看齐，实现属于自己的DL框架。PyDyNet已被多个技术公众号和社区分享：居然用Numpy实现了一个深度学习框架.更新日志5.10: ver 0.0.1 修改损失函数的定义方式：加入reduction机制，加入Embedding;5.15: ver 0.0.2 重构了RNN, LSTM和GRU，支持双向;5.16: ver 0.0.2 允许PyDyNet作为第三方库安装；开始手册的撰写(基于Sphinx).5.29: ver 0.0.3 加入了Dataset和Dataloader，现在可以像PyTorch一样定义数据集和分割数据集，具体参考data.py中的train_loader函数；5.30: ver 0.0.3 将一维卷积算法退化成基于循环的im2col，新版本NumPy似乎不是很支持strided上数组的魔改；7.22: ver 0.0.4/0.05 增加了Module类和Parameter类，将模块重组、增加多种Pytorch支持的初始化方式；正在撰写新的Manual；7.28: ver 0.0.6 加入no_grad方法，可以像pytorch一样禁止自动微分，比如@no_grad()和with no_grad()，详见autograd.py;8.09: ver 0.0.7 基于cupy，PyDyNet现在可以使用显卡加速训练，用法与PyTorch一致，详见tests中cu*.py；8.18: ver 0.0.8 加入学习率调整策略，实现了训练过程中自动调节学习率；10.21: ver 0.0.9 加入tensor的split方法，基于此改进了RNN；10.23: ver 0.0.10 重写RNN, LSTM和GRU，支持多层双向；...OverviewPyDyNet也是纯NumPy(0.0.7版本后加入CuPy，其用法和NumPy一致)实现的神经网络，语法受PyTorch的启发，大致结构如下：graph BT
   N(numpy.ndarray/cupy.ndarray) ----> ds(Dataset) ----> Data(DataLoader)--> Mission
   N --> A(Tensor) --Eager execution--> B(Basic operators: add, exp, etc)
   B -.Autograd-.-> A
   B --> CO(Complex operators:softmax,etc)
   --> f(Function:linear, conv2d, etc) 
   --> M(Basic Module:Linear,Conv2d,etc)
   --> CM(Advanced Module:CNN,RNN,etc)
   --> Mission(PyDyNet)
   N --> GD(Optimizer:SGD, Adam, etc) ----> LS(lr_scheduler:StepLR, etc)--> Mission虚线表示用户可以通过no_grad来关闭自动微分功能。文件结构pydynet
├──__init__.py
├──autograd.py# 微分控制模块├──cuda.py# cuda功能模块├──data.py# 数据集模块├──nn# 神经网络模块│├──__init__.py│├──functional.py# 函数类│├──init.py# 初始化模块│├──modules
││├──__init__.py
││├──activation.py# 激活函数││├──batchnorm.py# BN││├──conv.py# 卷积││├──dropout.py# Dropout││├──linear.py# 线性层││├──loss.py# 损失函数类││├──module.py# Module基类，包括Sequential││├──pool.py# 池化││└──rnn.py# RNN│└──parameter.py# 参数化类├──optim
│├──__init__.py
│├──lr_scheduler.py# 学习率衰减策略│└──optimizer.py# 优化器类└──tensor.py# 张量类我们实现了：将NumPy数组包装成具有梯度等信息的张量(Tensor):ExamplefrompydynetimportTensorx=Tensor(1.,requires_grad=True)print(x.data)# 1.print(x.ndim,x.shape,x.is_leaf)# 0, (), True将NumPy数组的计算(包括数学运算、切片、形状变换等)抽象成基础算子(Basic operators)，并对部分运算加以重载：ExampleimportpydynetaspdnfrompydynetimportTensorx=Tensor([1,2,3])y=pdn.exp(x)+xz=pdn.sum(x)print(z.data)# 36.192...手动编写基础算子的梯度，实现和PyTorch相同的动态图自动微分机制(Autograd)，从而实现反向传播ExampleimportpydynetaspdnfrompydynetimportTensorx=Tensor([1.,2.,3.],requires_grad=True)y=pdn.log(x)+xz=pdn.sum(y)z.backward()print(x.grad)# [2., 1.5, 1.33333333]基于基础算子实现更高级的算子(Complex operators)，它们不再需要手动编写导数：Exampleimportpydynetaspdndefsimple_sigmoid(x:pdn.Tensor):return1/(1+pdn.exp(-x))实现了Mudule，包括激活函数，损失函数等，从而我们可以像下面这样定义神经网络，损失函数项：Exampleimportpydynet.nnasnnimportpydynet.nn.functionalasFn_input=64n_hidden=128n_output=10classNet(nn.Module):def__init__(self)->None:super().__init__()self.fc1=nn.Linear(n_input,n_hidden)self.fc2=nn.Linear(n_hidden,n_output)defforward(self,x):x=self.fc1(x)x=F.sigmoid(x)returnself.fc2(x)net=Net()loss=nn.CrossEntropyLoss()l=loss(net(X),y)l.backward()实现了多种优化器和学习率衰减策略，从而实现神经网络的训练；其中优化器和PyTorch一样支持权值衰减，即正则化：Examplefrompydynet.optimimportAdam,StepLR...net=Net()optimizer=Adam(net.parameters(),lr=0.01)lr_scheduler=StepLR(optimizer,step_size=10)forepochinrange(EPOCHES):fordataindata_loader:train(...)optimizer.step()lr_scheduler.step()实现了Dataset和DataLoader对数据集进行加载与划分：Examplefrompydynet.dataimportDataset,DataLoaderclassTrainSet(Dataset):def__init__(self,X,y)->None:self.data=Xself.target=ydef__getitem__(self,index):returnself.data[index],self.target[index]def__len__(self):returnlen(self.data)data_loader=DataLoader(TrainSet(X,y),batch_size,shuffle)Dropout机制，Batch Normalization机制，以及将网络划分成训练阶段和评估阶段；基于im2col高效实现Conv1d, Conv2d, max_pool1d和max_pool2d，从而实现CNN；支持多层的多层双向RNN，LSTM和GRU；多种初始化方式，包括Kaiming和Xavier；基于cupy实现了显卡计算和训练：ExamplefrompydynetimportTensorx=Tensor([1.,2.,3.],device='cuda')y=Tensor([1.,2.,3.],device='cuda')z=(x*y).sum()w=Tensor([1.,2.,3.])# CPU上的Tensorx*w# 报错Installpipinstallpydynet或本地安装gitclonehttps://github.com/Kaslanarian/PyDyNetcdPyDyNet
pythonsetup.pyinstall安装成功后就可以运行下面的例子Exampletests中是一些例子。AutoDiffautodiff.py利用自动微分，对一个凸函数进行梯度下降：DNNDNN.py使用全连接网络对sklearn提供的数字数据集进行分类，训练参数网络结构：Linear(64->64) + Sigmoid + Linear(64->10)；损失函数：Cross Entropy Loss；优化器：Adam(lr=0.01)；训练轮次：50；批大小(Batch size)：32.训练损失，训练准确率和测试准确率：CNNCNN.py使用三种网络对fetch_olivetti_faces人脸(64×64)数据集进行分类并进行性能对比：Linear + Sigmoid + Linear;Conv1d + MaxPool1d + Linear + ReLU + Linear;Conv2d + MaxPool2d + Linear + ReLU + Linear.其余参数相同：损失函数：Cross Entropy Loss；优化器：Adam(lr=0.01)；训练轮次：50；批大小(Batch size)：32.学习效果对比：Droput & BNdropout_BN.py使用三种网络对fetch_olivetti_faces人脸(64×64)数据集进行分类并进行性能对比：Linear + Sigmoid + Linear;Linear + Dropout(0.05) + Sigmoid + Linear;Linear + BN + Sigmoid + Linear.其余参数相同：损失函数：Cross Entropy Loss；优化器：Adam(lr=0.01)；训练轮次：50；批大小(Batch size)：32.学习效果对比：RNNRNN.py中是一个用双向单层GRU对sklearn的数字图片数据集进行分类：cuda相关cuDNN.py,cuCNN.py,cuDropoutBN.py,cuRNN.py分别是上面四种网络的cuda版本，并对网络进行了相应的修改，主要是介绍如何使用PyDyNet的显卡功能，且已经在无显卡和有显卡的环境下都通过了测试。NetDatasetParametersCPU timeGPU timeFCDigits (1970×64)batch_size=128, epoch=5030.8s±392ms22.4s±298msCNN1dOlivettiFaces (400×4096)batch_size=64, epoch=508.76s±68.7ms4.49s±16.3msCNN2dOlivettiFaces (400×4096)batch_size=64, epoch=5014.1s±285ms4.54s±49ms事实上，对于越庞大的网络（更宽，更深，卷积），GPU加速效果更好。