日常tricks

tricks

1.Mxnet Dataloder __getitem__相关

for循环迭代时,如果对象不具有iterator接口,就会调用类的__getitem__魔法函数(前提是定义了),上述的__getitem__把类变成了序列,所以可切片可遍历:

class _DownloadedDataset(Dataset):
    """Base class for MNIST, cifar10, etc."""

    def __init__(self, root, transform):
        super(_DownloadedDataset, self).__init__()
        self._transform = transform
        self._data = None
        self._label = None
        root = os.path.expanduser(root)
        self._root = root
        if not os.path.isdir(root):
            os.makedirs(root)
        self._get_data()

    def __getitem__(self, idx):
        if self._transform is not None:
            return self._transform(self._data[idx], self._label[idx])
        return self._data[idx], self._label[idx]

    def __len__(self):
        return len(self._label)

    def _get_data(self):
        raise NotImplementedError  

之前困惑的地方是:Dataloader传入的参数是Dataset,data和label是绑定的,而且下面的程序中:

def __iter__(self):  
       if self._num_workers == 0:  
           def same_process_iter():  
               for batch in self._batch_sampler:  
                   ret = self._batchify_fn([self._dataset[idx] for idx in batch])  
                   if self._pin_memory:  
                       ret = _as_in_context(ret, context.cpu_pinned(self._pin_device_id))  
                   yield ret  
           return same_process_iter()  

[self._dataset[idx] for idx in batch]不知道是如何使用idx同时返回label和data,实际上他们是通过__getitem__实现的

2. 增加维度

①使用reshape:有些时候会报错

	X = np.random.randn(1,2,4)  
	X.reshape((1,1,2,4))  
	Out[6]:   
	array([[[[-0.72891874,  1.71191095,  0.63739902, -0.51441055],  
	         [-0.92141293, -0.7134368 , -0.35407003, -1.87953331]]]])  

②使用np.newaxis np矩阵可用,mxnet的nd矩阵不可用

	X = X[:,np.newaxis,:,:]  
	X.shape  
	Out[10]: (1, 1, 2, 4)  
	print(X)  
	[[[[-0.72891874  1.71191095  0.63739902 -0.51441055]  
	   [-0.92141293 -0.7134368  -0.35407003 -1.87953331]]]] 

③使用nd.expand_dim()

	X = nd.random.randn(1,2,4)  
	X = nd.expand_dims(X,1)  
	X  
	Out[17]:   
	[[[[ 1.1630785   0.4838046   0.29956347  0.15302546]  
	   [-1.1688148   1.558071   -0.5459446  -2.3556297 ]]]]  
	<NDArray 1x1x2x4 @cpu(0)>  
	X.shape  
	Out[18]: (1, 1, 2, 4)  

3. 延后初始化

	kernel = bilinear_kernel(1,1,3)  
	net = Unet(1,4)  
	net.initialize(force_reinit=False)  
	X = nd.random.randn(1,1,512,512)  
	# weight = nd.random.randn(1,64,2,2)  
	# a.set_data(weight)  
	y = net(X)  
	a = net.collect_params().__getitem__('upsample4_weight')  
	print(a.data().shape)  
	print(y.shape)  
	# print(a.data())  

Mxnet的特性是:当调用initialize()时网络并不知道具体的权重的shape是多少,在进行第一次前向传播之后才真正获得权重的具体信息,因此如果在初始化和前向传播之间对权重进行操作会报错如下所示:这就是我们所说的延后初始化。

	kernel = bilinear_kernel(1,1,3)  
	net = Unet(1,4)  
	net.initialize(force_reinit=False)  
	X = nd.random.randn(1,1,512,512)  
	# weight = nd.random.randn(1,64,2,2)  
	# a.set_data(weight)  
	a = net.collect_params().__getitem__('upsample4_weight')  
	print(a.data().shape)  
	y = net(X)  
	print(y.shape)  
	# print(a.data())  

避免上述问题的方法:
1)、手动写出输入输出channels
2)、在对data进行操作之前进行一次前向计算

4. mxnet customop

class Dense(mx.operator.CustomOp):
    def __init__(self, bias):
        self._bias = bias

    def forward(self, is_train, req, in_data, out_data, aux):
        x = in_data[0].asnumpy()
        weight = in_data[1].asnumpy()
        y = x.dot(weight.T) + self._bias
        self.assign(out_data[0], req[0], mx.nd.array(y))

    def backward(self, req, out_grad, in_data, out_data, in_grad, aux):
        x = in_data[0].asnumpy()
        dy = out_grad[0].asnumpy()
        dx = dy.T.dot(x)
        self.assign(in_grad[0], req[0], mx.nd.array(dx))

@mx.operator.register("dense")  # register with name "sigmoid"
class DenseProp(mx.operator.CustomOpProp):
    def __init__(self, bias):
        super(DenseProp, self).__init__(True)
        # we use constant bias here to illustrate how to pass arguments
        # to operators. All arguments are in string format so you need
        # to convert them back to the type you want.
        self._bias = float(bias)

    def list_arguments(self):
        return ['data', 'weight']

    def list_outputs(self):
        #  this can be omitted if you only have 1 output.
        return ['output']

    def infer_shape(self, in_shapes):
        data_shape = in_shapes[0]
        weight_shape = in_shapes[1]
        output_shape = (data_shape[0], weight_shape[0])
        # return 3 lists representing inputs shapes, outputs shapes, and aux data shapes.
        return (data_shape, weight_shape), (output_shape,), ()

    def create_operator(self, ctx, in_shapes, in_dtypes):
        #  create and return the CustomOp class.
        return Dense(self._bias)

class DenseBlock(mx.gluon.HybridBlock):
    def __init__(self, in_channels, channels, bias, **kwargs):
        super(DenseBlock, self).__init__(**kwargs)
        self._bias = bias
        self._weight = mx.gluon.Parameter("weight", shape=(channels, in_channels),init=mx.init.Xavier())
        self._weight.initialize()

    def hybrid_forward(self, F, x, *args, **kwargs):
        ctx = x.context
        return F.Custom(x, self._weight.data(ctx), bias=self._bias, op_type='dense')

if __name__ == "__main__":
    dense = DenseBlock(3, 5, 0.1)
    dense.initialize()
    x = mx.nd.uniform(shape=(4, 3))
    y = dense(x)
    print(y)
    print("done")

以上是动态图的写法,静态图不可用,原因是在最后一层封装DenseBlock中的hybrid_forward使用了ctx = x.context,self._weight.data(ctx);静态图中,hybrid_forward中参与计算的必须是symbol类型self._weight.data(ctx)是ndarray类型。
而forward中可以进行nd的一些列操作:

class CustomAdd(mx.operator.CustomOp):
    def __init__(self):
        super(CustomAdd, self).__init__()

    def forward(self, is_train, req, in_data, out_data, aux):
        x = in_data[0]
        b = in_data[1]
        y = out_data[0]
        ctx = b.context
        x = x.as_in_context(context=ctx)
        y[:] = nd.add(x, b)
        self.assign(out_data[0], req[0], y)

    def backward(self, req, out_grad, in_data, out_data, in_grad, aux):
        pass

5.手动设置卷积核权重weight:

kernel = bilinear_kernel(1,1,3)  
net = Unet(1,4)  
net.initialize(force_reinit=False)  
X = nd.random.randn(1,1,512,512)  
y = net(X)  
weight = nd.random.randn(128,64,2,2)  
a = net.collect_params().__getitem__('upsample4_weight')  
a.set_data(weight)  
print(a.data().shape)  

也可以使用以下语句获得权重字典:

a = net.collect_params().items() 

6.转置卷积和空洞卷积(膨胀卷积)的区别

7.tensorflow卷积操作中的“SAME”和“VALID”

①tensorflow padding=“SAME”输入输出大小关系:

②tensorflow padding=“VALID”

8.mxnet pad()方法:

在使用mxnet编写u-net网络式时,涉及到了对两个不同大小的卷积结果进行concat(channel级别的拼接)操作,这就要求待拼接的两个4D矩阵的后面两个维度完全相同,因此需要对小的矩阵进行padding操作,如下所示:

	a = mx.nd.pad(data_a,mode="edge",pad_width=(0,0,0,0,0,1,0,1))  
	a  
	Out[63]:   
	[[[[ 0.29670075  1.3111951   0.5035904   0.5035904 ]  
	   [-1.189445   -0.55021375 -1.5918757  -1.5918757 ]  
	   [-1.1081947   0.0787202  -0.9185634  -0.9185634 ]  
	   [-1.1081947   0.0787202  -0.9185634  -0.9185634 ]]]]  
	<NDArray 1x1x4x4 @cpu(0)>  
	data_a  
.	Out[64]:   
	[[[[ 0.29670075  1.3111951   0.5035904 ]  
	   [-1.189445   -0.55021375 -1.5918757 ]  
	   [-1.1081947   0.0787202  -0.9185634 ]]]]  
	<NDArray 1x1x3x3 @cpu(0)>  

需要特别说明的是:pad()中pad_width=(0,0,0,0,0,1,0,1)其含义为(dim0_before,dim0_after,…dim3_before,dim3_after)
这里的before和after表示需要说明一下:假如dim3_before = 0,dim3_after=1就表示需要在4D矩阵(batch,channel,行,列)的最后一列后padding,如果dim2_before = 1,dim2_after=0表示要在第一行前padding

	#padding前  
	Out[64]:   
	[[[[ 0.29670075  1.3111951   0.5035904 ]  
	   [-1.189445   -0.55021375 -1.5918757 ]  
	   [-1.1081947   0.0787202  -0.9185634 ]]]]  
	#padding 后  
	Out[63]:   
	[[[[ 0.29670075  1.3111951   0.5035904   0.5035904 ]  
	   [-1.189445   -0.55021375 -1.5918757  -1.5918757 ]  
	   [-1.1081947   0.0787202  -0.9185634  -0.9185634 ]  
	   [-1.1081947   0.0787202  -0.9185634  -0.9185634 ]]]]  
	  
	# 对应的pad_width=a = (0,0,0,0,0,1,0,1)  

9.日志logging相关

https://www.cnblogs.com/nancyzhu/p/8551506.html

10. 卷积的边界问题

11. python __call__方法

包含有该方法的对象,就是可调用对象;亦可以通过该方法使得类可以直接调用该方法。

12. python子类重写父类方法报错

Python中有一个LSP原则(在使用父类的场景,替换为子类一样可行),如果子类更改了父类方法的参数,就违反了该原则,解决办法是将子类方法的新增参数默认值设置为None

13. mxnet梯度计算、传播流程

	with autograd.record():  
	    y_hat = net(X)  
	    print(y_hat.shape)  
	    l = loss(y_hat, y)  
	l.backward()  

问题:当进行到loss.backward()这句时,gluon是怎么知道这个loss是对应于net的参数的呢?
record()函数调用_RecordingStateScope()函数,该方法中包含__enter__和__exit__方法,这两个方法保证了record函数支持上下文管理器协议,with语句开始调用__enter__方法,结束后调用__exit__方法。
with开始后,通过上下文管理器进入_RecordingStateScope类的,enter()方法中,调用set_recording()方法,计算梯度值.

14. mxnet hybrid方法注意事项

Hybrid方法是在调用net.hybridize()方法后,将计算图固化为静态图,所有在计算图中的节点传递的数据全部变成了ndarray,因此调用到ndarray专有属性的方法全部报错,如ndarray.shape
关于hybridblock的一些试验:
1、试验继承nn.HybridBlock子类初始化可以调用方法
2、hybrid_forward中同样可以调用自定义的方法

15. mxnet symbol获得shape的方法

Mxnet可以通过symbol.infer_shape()函数返回symbol的shape,
a.infer_shape()
Out[24]: ([], [(1, 1, 2, 2)], [])
第一个是arg_shape, 第二个是out.shape,最后一个是aux.shape()
https://github.com/apache/incubator-mxnet/issues/2763

16. Super()继承

使用super进行类继承如下:
class DenseVLossSimple(loss.Loss):??
def init(self,?weight=None,?batch_axis=0,?softmax=None,?**kwargs):??
super(DenseVLossSimple,?self).init(weight,?batch_axis,?**kwargs)??
self.softmax?=?softmax??
self._batch_axis?=?batch_axis??
如果super().init(params)中的参数与父类中的不同就会报错,原因是super后面继承的是父类的方法,一般情况下继承父类初始化方法,既然继承父类方法,必须参数与父类一致.

17. 深入理解信息熵与交叉熵以及softmax、sigmoid搭配选择

1.交叉熵与信息熵:
信息熵代表的是随机变量或整个系统的不确定性,熵越大,随机变量或系统的不确定性就越大。根据真实分布,我们能够找到一个最优策略,以最小的代价消除系统的不确定性,而这个代价大小就是信息熵,记住,信息熵衡量了系统的不确定性,而我们要消除这个不确定性,所要付出的【最小努力】(猜题次数、编码长度等)的大小就是信息熵。

交叉熵,表征的是两个不同分布的随机变量、系统的相似程度,交叉熵越大越不相似。因此可以被用来衡量真实分布与非真实分布之间的相似程度。

相对熵:用来衡量两个取正的函数或者系统的相似程度。

2.深度学习中的softmax、sigmoid
首先,softmax的soft体现在普通的max函数是只产生最大值,而softmax不仅产生了最大值,而是将每一个值由小到大都都给出了概率,当softmax针对二分类时(只有0,1两个类别),那么softmax就退化为了sigmoid。
使用softmax与交叉熵配合的时候,假设一组数据的预测结果类别N=3,期望输出为p=(1,0,0),实际输出(原始数据):q1=(0.5,0.2,0.3),q2=(0.8,0.1,0.1),那么交叉熵为:

对于语义分割问题:如果使用softmax函数,那么问题属于一个多分类的问题,输出结果经过softmax就变为每个结果的概率。交叉熵损失是针对每一个像素的预测结果计算损失的,假设图像分割又N个标签,那么对于每一个像素生成留个分类结果向量,使用交叉熵计算结果与真实label的相似程度。那么就需要将label从1,2,3,4.。。。转换为one-hot向量,如:[1,0,0,0,…],[0,1,0,0,0…],可能也需要将背景也作为一个标签。
如果使用sigmoid函数,那么相当于每个label是相互独立的,相互之间没有影响,如果输出N标签,每个标签的结果都只有01两个结果,是不互相影响的,那么交叉熵就是一个二项分布:

对于Densevnet项目而言,输出结果为batch_size,numclass,144^3, label只有两个参考值分别是0,1。因此应该使用sigmoid+二元交叉熵,而我是使用多元softmax还搭配二元交叉熵,未经过one-hot编码的label效果肯定不好。

18. Mxnet gluon 编程注意事项:

1.类尽量初始化后再使用,尽量不要出现一下情况:
Class Block
Out = Block(init)(args1, args2)
实际使用过程中,如类Blockb不需要参数初始化,如:
out = Block()(args1,args2)
不会报错,但是如果在使用的同时进行参数初始化就会出错。
2.使用hybrid过程中,hybrid_forward()函数传参尽量不要传递非symbol参数,如果要是用symbol相关数据,尽量写成类的属性(成员变量)

19. Cuda unspecified launch failure?错误

怀疑是因为分别存在于两个GPU中的数据进行运算操作而引起的,可以通过将矩阵转化为numpy的形式解决上述问题,Ndarray.asnumpy()cv.resize函数的使用说明
def resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)
scr可以是mat矩阵也可以是numpy矩阵.

20. cv.resize函数的使用说明

def resize(src, dsize, dst=None, fx=None, fy=None, interpolation=None)
scr可以是mat矩阵也可以是numpy矩阵。

21. Lambda表达式函数传参:

1.应用背景:

给button链接函数的同时需要传递参数
2.实验:如果没有lambda那么参数中command就是一个函数返回值,表示函数。如果command=self,cancel_mpb,虽然command表示是cancel_mpb的函数,但是调用的时候必须给command传递参数。使用lambda表达式后command的就是绑定了一个动态参数的函数。(途中的_mpb, _top可以动态变化)巧妙运用lambda表达式,将command替换为func函数
3.代码示例:

输出:

22. 损失函数对于离散值得处理方法

1.需要找到一个评价预测值(预测值往往都是连续的)和离散的ground truth相似性的函数,2. 将离散数据处理成可以连续表示的数据,比如说是使用one hot编码将离散label可以与softmax处理后的连续值比较。

23. Softmax与sigmoid的理解

1.Softmax的公式为:

S1+S2+S3…=1,所以说如果使用softmax进行多分类问题,潜在的说明这些类别是相关的,这些类别是互斥的(比如说图像分割一个像素点不能属于两个类别),而sigmoid处理后没有相关性。

24. C++形式参数,实际参数(传址,传引用地址等)

C++对所有形式参数均申请一份内存空间复制实际参数的值,也就说形式参数只是实际参数值得拷贝,如果函数传参使用传地址(指针)的方式,函数内对地址形式参数的修改都是对实参的拷贝修改,并不会改变指针的指向(不会改变地址值),但是如果对指针指向的内存的内容修改,那么实参的指针的指向值也会改变,如果想要使用函数改变地址的指向,那么就要使用地址的引用,引用的形参就是实参的别名,不是实参的拷贝,因此可以可以改变实参的值(如果实参是指针那么改变的就是指向的内存编号)。

25. Void* 指针可以指向任何类型的数据

26. Python 通过ctypes调用C++接口返回值为char*

1.Ctypes与c数据类型对照关系如下:

2.Python代码

# -*- coding: utf-8 -*-
import ctypes
DLLPATH = "D:\\dataset\\unmarked\\20180607_GUO BAO LIN\\T_2_112306.520_236\\Liver_OutLine.mhd"
testdll = ctypes.cdll.LoadLibrary("D:\\CppProject\\creatdll\\x64\\Release\\_GetNoZeroLabelIDIndex.dll")
Test = testdll._Test
Test.argtypes=[ctypes.c_char_p]  //设置输入参数类型
Test.restype = ctypes.c_char_p  //设置返回值类型
path = Test(ctypes.c_char_p(DLLPATH.encode("ascii")))
print(str(path, encoding='utf-8', errors='ignore'))
print('done')

3.Cpp代码
.h文件:

vector<string> ParsingPath(string Path);
extern "C" _declspec(dllexport) char* _Test(char* pchPath);
extern "C" _declspec(dllexport) int* _GetNoZeroLabelIDIndex(char* pchPath, int nClaseeid);
.cpp:
char* _Test(char* pchPath)
{
	string sTmp = pchPath;
	char* chOut = nullptr;
	char chStr[_MAX_DIR];
	sTmp.copy(chStr, sTmp.length(), 0);
	chStr[sTmp.length()] = '\0';
	cout << chStr << endl;
	chOut = chStr;
	return chOut;
}

需要注意的是:如果C借口中有使用到string类型,那么只能通过以上方法将string转换成char类型,使用其他方法无效,python端无法解析完整返回的char

27. Numpy数据使用ctypes传递给C接口

Python:

Test = CustomDll._Test
Test.argtypes = [np.ctypeslib.ndpointer(dtype=np.uint8, ndim=2, flags='CONTIGUOUS')]
Test.restype =cp.c_bool
listIndex = []
array = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.uint8)
print(array.shape)
print(Test(array))

Cpp:

bool _Test(int* pchPath)
{
	char* tmp = (char*)pchPath;
	for (int i = 0; i < 3;i++)
	{
		//cout << (tmp[i] == 3) << endl;
		printf("%d\n", tmp[i]);
	}
	return true;
}

需要注意的是红色部分,数据格式一定要意义的对应,char对应的是uint8,如果不是uint8那么就会出现显示不正确的情况,np数据会被截断。Python中如果传输数据不可以使用char/c_char类型,python默认char就是字符,默认转换为byte传输,并不是向c中char和int/short可以随意强制转换。

28. 可以使用指针来维护numpy的值,解决了返回内存泄漏的问题

Test = CustomDll._Test
Test.argtypes = [np.ctypeslib.ndpointer(dtype=np.int, ndim=1, flags='CONTIGUOUS')]
Test.restype = cp.c_bool
tmp = np.array([0, 0, 0, 0, 0, 0]).astype(dtype=np.int)
print(Test(tmp))
print(tmp)
bool _Test(int* pnData)
{
	for (int i = 0; i < 3;i++)
	{
		pnData[i] = 1;
	}
	return true;
}

将numpy矩阵首地址传入C,C程序中维护矩阵的值,但是numpy对应的地址空间是python来维护的解决了内存泄漏的问题。
2.写一个C函数专门释放内存

FreeIntArr = CustomDll.FreeIntMen
FreeIntArr.argtypes = [cp.POINTER(cp.c_int)]
FreeIntArr.restype = cp.c_bool
bool FreeIntMen(int* pnData)
{
	delete[] pnData;
	return true;
}

但是这个有一个缺点就是,无法将原来的指针置为null,变成野指针。

29. CT图像的各项同性

在做resize的时候一定要注意各项同性的问题,不做resize不用考虑。

30. 梯度、方向导数、SGD、反向传播

1.梯度:梯度的定义如下所示:

梯度存在的一个重要的条件就是存在连续的偏导数。
梯度始终是方向导数的模,所以说梯度始终是为正的,在此处的最大的方向导数(各个方向的导数)为正,一元函数的导数为正说明函数是递增函数,从而引申到多元函数中方向导数为正那么说明沿着该方向运动函数值是变大的。
梯度下降法参数更新策略如下:

其中w为参数,为关于w的损失函数的梯度。
前面已经说到了,梯度是函数变大最快的方向,负梯度就是参数变小最快的方向,所以参照关于w的梯度调整w,就可以使得损失函数一步步的变小。

31. 反向传播的矩阵形式推导

疑问:这里面的dw,dx,db求解方法有疑惑,正常情况向不是应该dw=nd.dot(dy, x)?
解释:差别在于前向计算定义的不同导致的,dw=nd.dot(dy, x)这个公式是因为神经网络前向传播的定义为:y = XW + b,如果定义为y = XW.T + b那么反向传播的公式就要重新推导,如上所示了。

32. simple itk坐标

注意simple itk 坐标是zyx

33. lr_scheduler.CosineScheduler()参数说明

cosine学习率更新规则公式:
l r = f i n a l _ l r + ( s t a r t _ l r − f i n a l _ l r ) ∗ ( 1 + cos ⁡ ( π ∗ c u r r e n t _ u p d a t e / m a x _ u p d a t e ) ) / 2 lr=final\_lr+(start\_lr-final\_lr)*(1+\cos(\pi*current\_update/max\_update))/2 lr=final_lr+(start_lrfinal_lr)(1+cos(πcurrent_update/max_update))/2

  • max_update (int) – maximum number of updates before the decay reaches 0
  • base_lr (float) – base learning rate
  • final_lr (float) – final learning rate after all steps
  • warmup_steps (int) – number of warmup steps used before this scheduler starts decay
  • warmup_begin_lr (float) – if using warmup, the learning rate from which it starts warming up
  • warmup_mode (string) – warmup can be done in two modes. ‘linear’ mode gradually increases lr with each step in equal increments ‘constant’ mode keeps lr at warmup_begin_lr for warmup_steps

参数中的step和update是参数更新的次数,如果一次训练(epoch)需要进行204800次迭代计算,那么1epoch训练lr调整了204800/batch size次。以此来计算参数、设定参数。

34.mxnet 获取中间symbol

mxnet获取中间值的方法主要是使用Symbol.get_internals()函数,先打印其结果再通过以下方式实现:

sub_symbol = net.get_internals()['internal_sym']

值得注意的是,对于一些不带参数的操作的输出值后面要加上’_output’,如想要取得relu的输出值如下所示:

sub_symbol = net.get_internals()['relu_output']

35.验证集测试集训练集

训练集和验证集用于算法的训练过程,验证集是训练集划分而来验证模型的收敛程度,测试集用于评估训练模型的参数对应用场景的性能。

36.vs2015控制台程序和DLL生成转换

生成动态链接库模式:
在这里插入图片描述
在这里插入图片描述
执行main函数,控制台模式:
在这里插入图片描述
在这里插入图片描述

深度学习tricks是指在深度学习模型训练过程中使用的一些技巧和策略,旨在提高模型的性能和训练效果。以下是一些常用的深度学习tricks: 1. 数据增强(Data Augmentation):通过对原始数据进行随机变换和扩充,生成更多的训练样本,以增加模型的泛化能力。 2. 批归一化(Batch Normalization):在每个小批量数据上进行归一化操作,有助于加速模型的收敛速度,提高模型的稳定性和泛化能力。 3. 学习率调整(Learning Rate Schedule):根据训练的进程动态地调整学习率,例如使用学习率衰减或者学习率预热等策略,以提高模型的收敛性能。 4. 正则化(Regularization):通过添加正则化项,如L1正则化或L2正则化,限制模型的复杂度,防止过拟合。 5. 提前停止(Early Stopping):在训练过程中监控验证集上的性能指标,当性能不再提升时停止训练,以避免过拟合。 6. 参数初始化(Parameter Initialization):合适的参数初始化可以帮助模型更快地收敛和更好地泛化,常用的初始化方法包括Xavier初始化和He初始化等。 7. 梯度裁剪(Gradient Clipping):限制梯度的范围,防止梯度爆炸或梯度消失问题,提高模型的稳定性。 8. 集成学习(Ensemble Learning):通过结合多个模型的预测结果,可以提高模型的泛化能力和鲁棒性。 9. 迁移学习(Transfer Learning):利用已经训练好的模型在新任务上进行微调,可以加快模型的训练速度和提高模型的性能。 10. 深度网络结构设计:合理设计网络结构,包括层数、宽度、卷积核大小等,可以提高模型的表达能力和学习能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值