Skip to content

Commit

Permalink
add write a new model file
Browse files Browse the repository at this point in the history
write a new model file final  edition

write a new model file final2  edition

write a new model file clean code
  • Loading branch information
chenyang23333 committed Jul 11, 2023
1 parent 3f08bad commit 5523dc2
Showing 1 changed file with 222 additions and 1 deletion.
223 changes: 222 additions & 1 deletion docs/zh/how_to_guides/write_a_new_model.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,223 @@
# 模型编写指南
即将到来
本文档提供MindYOLO编写自定义模型的教程。<br>
分为三个部分:
- 模型定义:我们可以直接定义一个网络,也可以使用yaml文件方式定义一个网络。
- 注册模型:可选,注册之后可以在create_model接口中使用文件名创建自定义的模型
- 验证: 验证模型是否可运行

## 模型定义
### 1.直接使用python代码来编写网络
### 模块导入
导入MindSpore框架中的nn模块和ops模块,用于定义神经网络的组件和操作。
```python
import mindspore.nn as nn
import mindspore.ops.operations as ops
```

### 创建模型
定义了一个继承自nn.Cell的模型类MyModel。在构造函数__init__中,定义模型的各个组件:

```python
class MyModel(nn.Cell):
def __init__(self):
super(MyModel, self).__init__()
#conv1是一个2D卷积层,输入通道数为3,输出通道数为16,卷积核大小为3x3,步长为1,填充为1。
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
#relu是一个ReLU激活函数操作。
self.relu = ops.ReLU()
#axpool是一个2D最大池化层,池化窗口大小为2x2,步长为2。
self.maxpool = nn.MaxPool2d(kernel_size=2, stride=2)
#conv2是另一个2D卷积层,输入通道数为16,输出通道数为32,卷积核大小为3x3,步长为1,填充为1。
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
#fc是一个全连接层,输入特征维度为32x8x8,输出特征维度为10。
self.fc = nn.Dense(32 * 8 * 8, 10)

#在construct方法中,定义了模型的前向传播过程。输入x经过卷积、激活函数、池化等操作后,通过展平操作将特征张量变为一维向量,然后通过全连接层得到最终的输出结果。
def construct(self, x):
x = self.conv1(x)
x = self.relu(x)
x = self.maxpool(x)
x = self.conv2(x)
x = self.relu(x)
x = self.maxpool(x)
x = x.view(x.shape[0], -1)
x = self.fc(x)
return x
```
### 创建模型实例
通过实例化MyModel类,创建一个模型实例model,后续可以使用该实例进行模型的训练和推理。
```python

model = MyModel()

```

## 2.使用yaml文件编写网络
通常需要以下三个步骤
- 新建一个mymodel.yaml文件
- 新建对应的mymodel.py文件
- 在mindyolo/models/_init_.py文件中引入该模型

### 以下是编写mymodel.yaml文件的详细指导
以编写一个简单网络为例:
以yaml格式编写必要参数,后续在mymodel.py文件里面可以用到这些参数。
其中network部分为模型网络 <br>
[[from, number, module, args], ...]:每个元素代表一个网络层的配置。<br>
```yaml
# __BASE__中的yaml表示用于继承的基础配置文件,重复的参数会被当前文件覆盖;
__BASE__:
- '../coco.yaml'
- './hyp.scratch-high.yaml'

per_batch_size: 32
img_size: 640
sync_bn: False

network:
model_name: mymodel
depth_multiple: 1.0 # model depth multiple
width_multiple: 1.0 # layer channel multiple
stride: [ 8, 16, 32 ]

# 骨干网络部分的配置,每层的元素含义为
# [from, number, module, args]
# 以第一层为例,[-1, 1, ConvNormAct, [32, 3, 1]], 表示输入来自 `-1`(上一层) ,重复次数为 1,模块名为 ConvNormAct,模块输入参数为 [32, 3, 1];
backbone:
[[-1, 1, ConvNormAct, [32, 3, 1]], # 0
[-1, 1, ConvNormAct, [64, 3, 2]], # 1-P1/2
[-1, 1, Bottleneck, [64]],
[-1, 1, ConvNormAct, [128, 3, 2]], # 3-P2/4
[-1, 2, Bottleneck, [128]],
[-1, 1, ConvNormAct, [256, 3, 2]], # 5-P3/8
[-1, 8, Bottleneck, [256]],
]

#head部分的配置
head:
[
[ -1, 1, ConvNormAct, [ 512, 3, 2 ] ], # 7-P4/16
[ -1, 8, Bottleneck, [ 512 ] ],
[ -1, 1, ConvNormAct, [ 1024, 3, 2 ] ], # 9-P5/32
[ -1, 4, Bottleneck, [ 1024 ] ], # 10
]
```
## 编写mymodel.py文件
### 模块导入
需要导入套件内的模块。 如`from .registry import register_model`等等

```python
import numpy as np
import mindspore as ms
from mindspore import Tensor, nn
from .initializer import initialize_defult #用于初始化模型的默认参数,包括权重初始化方式、BN 层参数等。
from .model_factory import build_model_from_cfg #用于根据 YAML 配置文件中的参数构建目标检测模型,并返回该模型的实例。
from .registry import register_model #用于将自定义的模型注册到 Mindyolo 中,以便在 YAML 配置文件中使用。
#可见性声明
__all__ = ["MYmodel", "mymodel"]
```
### 创建配置字典
_cfg函数是一个辅助函数,用于创建配置字典。它接受一个url参数和其他关键字参数,并返回一个包含url和其他参数的字典。<br>
default_cfgs是一个字典,用于存储默认配置。在这里,mymodel作为键,使用_cfg函数创建了一个配置字典。
```python
def _cfg(url="", **kwargs):
return {"url": url, **kwargs}
default_cfgs = {"mymodel": _cfg(url="")}
```
### 创建模型
在`MindSpore`中,模型的类继承于`nn.Cell`,一般来说需要重载以下两个函数:

- 在`__init__`函数中,应当定义模型中需要用到的module层。
- 在`construct`函数中定义模型前向逻辑。 <br>

```python
class MYmodel(nn.Cell):
def __init__(self, cfg, in_channels=3, num_classes=None, sync_bn=False):
super(MYmodel, self).__init__()
self.cfg = cfg
self.stride = Tensor(np.array(cfg.stride), ms.int32)
self.stride_max = int(max(self.cfg.stride))
ch, nc = in_channels, num_classes
self.nc = nc # override yaml value
self.model = build_model_from_cfg(model_cfg=cfg, in_channels=ch, num_classes=nc, sync_bn=sync_bn)
self.names = [str(i) for i in range(nc)] # default names
initialize_defult() # 可选,你可能需要initialize_defult方法以获得和pytorch一样的conv2d、dense层的初始化方式;
def construct(self, x):
return self.model(x)
```

## 注册模型(可选)
如果需要使用mindyolo接口初始化自定义的模型,那么需要先对模型进行**注册**和**导入**

**模型注册** <br>
```python
@register_model #注册后的模型可以通过 create_model 接口以模型名的方式进行访问;
def mymodel(cfg, in_channels=3, num_classes=None, **kwargs) -> MYmodel:
"""Get GoogLeNet model.
Refer to the base class `models.GoogLeNet` for more details."""
model = MYmodel(cfg=cfg, in_channels=in_channels, num_classes=num_classes, **kwargs)
return model
```
**模型导入** <br>

```python
#在mindyolo/models/_init_.py文件中添加以下代码

from . import mymodel #mymodel.py文件通常放在mindyolo/models/目录下
__all__.extend(mymodel.__all__)
from .mymodel import *
```

## 验证main

初始编写阶段应当保证模型是可运行的。可通过下述代码块进行基础验证:
首先导入所需的模块和函数。然后,通过解析配置对象。

```python
if __name__ == "__main__":
from mindyolo.models.model_factory import create_model
from mindyolo.utils.config import parse_config

opt = parse_config()
```
创建模型并指定相关参数,注意:如果要在create_model中使用文件名创建自定义的模型,那么需要先使用注册器@register_model进行注册,请参见上文 注册模型(可选)部分内容
```python
model = create_model(
model_name="mymodel",
model_cfg=opt.net,
num_classes=opt.data.nc,
sync_bn=opt.sync_bn if hasattr(opt, "sync_bn") else False,
)

```

否则,请使用import的方式引入模型

```python
from mindyolo.models.mymodel import MYmodel
model = MYmodel(
model_name="mymodel",
model_cfg=opt.net,
num_classes=opt.data.nc,
sync_bn=opt.sync_bn if hasattr(opt, "sync_bn") else False,
)
```
最后,创建一个输入张量x并将其传递给模型进行前向计算。
```python
x = Tensor(np.random.randn(1, 3, 640, 640), ms.float32)
out = model(x)
out = out[0] if isinstance(out, (list, tuple)) else out
print(f"Output shape is {[o.shape for o in out]}")
```


0 comments on commit 5523dc2

Please sign in to comment.