首页/文章/ 详情

多层感知机2-模型选择、欠拟合和过拟合学习笔记

1天前浏览3
机器学习的目标是发现某些模式,这些模式能捕捉到训练集潜在总体的规律;若做到了这点,对从未遇到过的个体,利用这些模式也可以进行评估风险。如何发现可泛化的模式是机器学习的根本问题。
过拟合:一个模型出现在训练集数据上拟合程度高,而在测试集(新数据)上的拟合能力差的现象称为过拟合(overfitting)。当训练误差明显低于验证误差即表明出现了严重的过拟合。用于对抗过拟合的技术称为正则化(regularization)。

一、训练误差和泛化误差

训练误差(training error):模型在训练数据集上计算得到的误差。
泛化误差(generalization error):模型应用在同样从原始样本的分布中抽取的无限多数据样本时,模型误差的期望值。问题是,泛化误差无法准确地计算。因为无限多数据样本是一个虚拟对象。在实际中,通过将模型应用于一个独立的测试集来估计泛化误差,该测试集由随机选取的、未曾在训练集中出现的数据样本构成。

二、模型选择

模型复杂性:对于神经网络,通常将需要更多训练迭代的模型视为复杂的,而需要早停(early stopping)的模型-即较少训练迭代周期, 就不那么复杂。统计学家认为,能够轻松解释任意事实的模型是复杂的,而表达能力有限但仍能很好地解释数据的模型可能更有现实用途。
模型选择:在机器学习中,通过评估几个候选模型后选择最终的模型。这个过程叫做模型选择。有时,需要进行比较的模型在本质上是完全不同的(如决策树与线性模型)。又有时,需要比较不同的超参数设置下的同一类模型。
K折交叉验证:将原始训练数据分成K个不重叠的子集;然后执行K次模型训练和验证,每次在K−1个子集上进行训练,并在剩余的一个子集(在该轮中没有用于训练的子集)上进行验证;最后,通过对K次实验的结果取平均来估计训练和验证误差。
欠拟合:若一个模型不能降低训练误差,这可能意味着模型过于简单(即表达能力不足),无法捕获试图学习的模式;同时训练误差和验证误差之间的泛化误差很小;此时可以用一个更复杂的模型以降低训练误差。这种现象被称为欠拟合(underfitting)。
模型过拟合和欠拟合评估:是否过拟合或欠拟合可能取决于模型复杂性和可用训练数据集的大小。如下图所示,模型越复杂训练误差将越小,但是泛化误差反而变大,因此在模型选择时,须同时平衡训练误差和泛化误差以提高模型的可用性。训练数据集中的样本过小,训练出来的模型可能出现严重的过拟合。对于许多任务,深度学习只有在有数千个训练样本时才优于线性模型。

三、权重衰减(Weight Decay)

权重衰减是一种正则化技术,通过给损失函数增加模型权重L2范数的惩罚(penalty)来让模型权重不要太大,以减小模型的复杂度,实现抑制模型的过拟合而提高模型的泛化性的目的。
数据扰动:训练数据点距离真实模型的偏离程度就是数据扰动。正则化的目标是减小方差或是说减小数据扰动所造成的影响
权重衰减的具体公式如下:

其中,L_0是原损失函数;λ是一个超参,负责控制权重衰减的强弱;||W||^2为模型参数的L2范数的平方。

从上面的公式,可得到如下结论:

  • 模型的权重越大,Loss就会越大;

  • λ越大,权重衰减的就越厉害;

  • 若λ过大,将导致原Loss的占比较低,最终使模型效果变差。

权重衰减的注意事项:

  • 权重衰减实际效果并不理想,尤其是当模型很复杂时,权重衰退的效果可能会更小;

  • 权重系数λ通常取1e-3;

  • 权重衰退通常不对bias做;

  • 权重衰减取值越大,对抑制模型的强度越大。但这并不说明越大越好,太大的话,可能会导致模型欠拟合。

四、暂退法(Dropout)

扰动的稳健性:函数不应该对其输入的微小变化敏感。在训练过程中,计算后续层之前向网络的每一层注入噪声。暂退法在前向传播过程中,计算每一内部层的同时注入噪声,这已经成为训练神经网络的常用技术。这种方法之所以被称为暂退法,主要是在训练过程中丢弃(drop out)一些神经元。在标准暂退法 正则化中,通过按保留的节点的分数进行规范化来消除每一层的偏差。换言之,每个中间活性值h以暂退概率p由随机变量h ′替换,如下所示:

根据此模型的设计,其期望值保持不变,即E[h′] = h。


来源:檐苔
控制
著作权归作者所有,欢迎分享,未经许可,不得转载
首次发布时间:2025-08-26
最近编辑:1天前
青瓦松
硕士 签名征集中
获赞 17粉丝 0文章 45课程 0
点赞
收藏
作者推荐

ANSA二次开发:获取与视角一致的单元法向量

在ANSA二次开发中经常获取当前视角下被选中单元和视角一致的法向量以备后续操作。本文主要通过创建视角向量和被选中单元的法向量来展示这一过程。首先,需要对中的错误进行更正:ansa中GetViewAngles函数旋转顺序为Z->Y->Z;且以顺时针为正,和一般笛卡尔坐标相反。因此有:import mathfrom typing import List, Tuplefrom ansa import basefrom ansa import constantsfrom ansa import calcclass ANSATYPE(object): ''' 不同求解器对应关键字名字 ''' @class method def eshell(cls, deck:int)->str: typDict:dict = { constants.LSDYNA: 'ELEMENT_SHELL', constants.ABAQUS:'SHELL', constants.NASTRAN: 'SHELL', constants.RADIOSS: 'SHELL', constants.ANSYS: 'SHELL', 22: 'SHELL', # OPTISTRUCT 23: 'SHELL' # MARC } try: _type = typDict[deck] except KeyError: raise ValueError('ERROR: 模型Deck设置有误') return _type @class method def node(cls, deck:int)->str: typDict:dict = { constants.LSDYNA: 'NODE', constants.ABAQUS:'NODE', constants.NASTRAN: 'GRID', constants.RADIOSS: 'NODE', constants.ANSYS: 'NODE', 22: 'GRID', # OPTISTRUCT 23: 'NODE' # MARC } try: _type = typDict[deck] except KeyError: raise ValueError('ERROR: 模型Deck设置有误') return _typeclass Vector(object): @class method def point2Point(cls, point1:List[float], point2:List[float], unit:bool=True)->List[float]: ''' 计算两点构成的向量. 向量由point1指向point2,即point2-point1 ''' if isinstance(point1, base.Entity): point1 = point1.position if isinstance(point2, base.Entity): point2 = point2.position vect:List[float] = [p2-p1 for p1, p2 in zip(point1, point2)] return cls.unit(vect) if unit else vect @staticmethod def unit(vector:List[float])->List[float]: ''' 将一个向量单位化 ''' return calc.Normalize(vector) @staticmethod def distance(point1:List[float], point2:List[float])->float: ''' 计算两点间的距离 ''' if isinstance(point1, base.Entity): point1 = point1.position if isinstance(point2, base.Entity): point2 = point2.position return math.dist(point1, point2) @class method def angleCos(cls, vector1:List[float], vector2:List[float])->float: ''' 计算两个空间向量的夹角的余弦值。 ''' unit_vect01 = cls.unit(vector1) unit_vect02 = cls.unit(vector2) return sum([v1*v2 for v1, v2 in zip(unit_vect01, unit_vect02)]) @staticmethod def angle(vector1:List[float], vector2:List[float])->float: ''' 计算两个空间向量的夹角,返回值以弧度形式存在 ''' return calc.CalcAngleOfVectors(vector1, vector2) @class method def elemNormal(cls, shellElem:base.Entity)->List[float]: ''' 根据单元的前三个节点计算单元的法向量 ''' vect:List[float] = base.GetNormalVectorOfShell(shellElem) if isinstance(vect, list): return vect else: nodeType:str = ANSATYPE.node(DECK) nodes:List[base.Entity] = base.CollectEntities(DECK, shellElem, nodeType, recursive=True) return cls.vec3Point(nodes[0], nodes[1], nodes[2]) @class method def vec3Point(cls, point1:List[float], point2:List[float], point3:List[float])->List[float]: ''' 计算空间三点构成平面的法向量 ''' vect1:List[float] = cls.point2Point(point1, point2) vect2:List[float] = cls.point2Point(point1, point3) return calc.CrossProduct(vect1, vect2)def getViewVector()->List[float]: ''' 通过视角函数获取视角旋转角并将其装换为视角向量 ''' # 获取视角转动角 angles:List[float] = base.GetViewAngles() angleRad = list(map(math.radians, angles)) angleSin: List[float] = list(map(math.sin, angleRad)) angleCos: List[float] = list(map(math.cos, angleRad)) # 计算视角向量三分量 x:float = -angleSin[1] y:float = angleSin[0]*angleCos[1] z:float = angleCos[0]*angleCos[1] return [x, y, z]def getShellViewVector(elem:base.Entity)->List[float]: ''' 名称: getShellViewVector 描述: 获取shell单元与当前视角方向一致的法向向量 参数: elem object shell类型单元 返回值: 返回一个向量(list),该向量表示输入shell单元与当前视角一致的单元法向量。 ''' # 对输入对象进行参数检查 if not isinstance(elem, base.Entity): raise TypeError('请输入ansa对象') shellType = ANSATYPE.eshell(DECK) elemType = elem.ansa_type(DECK) if elemType != shellType and elemType != 'SOLIDFACET': raise TypeError(f'''输入ansaType类型有误, 此函数要求输入的为shell单元或solid单元的表面类型(SOLIDFACET), 现输入类型为{elemType}''') # 获取单元法向量 elemVect:List[float] = Vector.elemNormal(elem) # 获取视角向量 viewVect:List[float] = getViewVector() # 计算两个向量的夹角,若为锐角,单元法向量为所求方向;若为钝角,单元法向量反方向为所求方向 angle:float = Vector.angle(elemVect, viewVect) if angle==-math.pi: raise ValueError(f'输入向量有误, 现输入向量为{elemVect}和{viewVect}, 请核查') if angle>math.pi/2.0: elemVect = [-vect for vect in elemVect] return elemVectdef calcCog(entities:List[base.Entity])->List[float]: ''' 名称: calcCog 描述: 计算输入的entities对象的cog 参数: entities List[base.Entity] 存在cog的可迭代对象或entity对象 返回值: 返回一个Cog向量(list) ''' if isinstance(entities, base.Entity): entities = [entities] length = len(entities) if length==0: return[0.0, 0.0, 0.0] if length==1: return base.Cog(entities[0]) x, y, z = 0.0, 0.0, 0.0 for ent in entities: cog = base.Cog(ent) x += cog[0] y += cog[1] z += cog[2] return [x/length, y/length, z/length]def getMinDistEntityFromPoint(point:List[float], entities:List[base.Entity])->base.Entity: ''' 名称: getMinDistEntityFromPoint 描述: 从输入的entities对象中选出距point最近的对象。 参数: point List[float] 参考点坐标 entities List[base.Entity] 存在cog的可迭代对象或entity对象 返回值: 返回距point点最近的对象。 ''' if not entities: return None if isinstance(entities, base.Entity): return entities if len(entities)==1: return entities[0] minDistance:float = math.inf minEntity:base.Entity = None for ent in entities: cog = base.Cog(ent) distance = Vector.distance(cog, point) if distance<minDistance: minDistance = distance minEntity = ent return minEntitydef main(): types:Tuple[str] = (ANSATYPE.eshell(DECK), 'SOLIDFACET') entities:List[base.Entity] = base.PickEntities(DECK, types, initial_type=types[0]) if not entities: return None if len(entities)==1: entity = entities[0] cog = base.Cog(entity) else: cog = calcCog(entities) entity = getMinDistEntityFromPoint(cog, entities) vect = getShellViewVector(entity) fields = {'XT': cog[0], 'YT': cog[1], 'ZT': cog[2], 'XH': cog[0]+vect[0], 'YH': cog[1]+vect[1], 'ZH': cog[2]+vect[2], 'Name': 'element normal vector'} base.CreateEntity(DECK, 'DEFINE_VECTOR', fields) viewVect = getViewVector() fields = {'XT': cog[0], 'YT': cog[1], 'ZT': cog[2], 'XH': cog[0]+viewVect[0], 'YH': cog[1]+viewVect[1], 'ZH': cog[2]+viewVect[2], 'Name': 'view vector'} base.CreateEntity(DECK, 'DEFINE_VECTOR', fields) return Noneif __name__ == '__main__': main()来源:檐苔

未登录
还没有评论
课程
培训
服务
行家
VIP会员 学习计划 福利任务
下载APP
联系我们
帮助与反馈