打卡
损失函数
损失函数(代价函数)是用来衡量模型预测值与真实值之间差异的函数,不同的损失函数适用于不同类型的问题。常用的损失函数有,均方误差损失(Mean Squared Error, MSE)、RMSE(Root MSE)、交叉熵损失(Cross-Entropy Loss)、对数损失(Log Loss)、Huber损失(Huber Loss)、绝对误差损失(Mean Absolute Error, MAE)。
- mindspore.ops.mse_loss 或 mindspore.nn.MSELoss 计算预测值与真实值之间差异的平方的平均值,它对于异常值比较敏感。
- mindspore.ops.binary_cross_entropy 或 mindspore.nn.BCEWithLogitsLoss 交叉熵损失主要用于衡量分类模型的性能,特别是二分类问题。它衡量的是模型预测的概率分布与真实标签的概率分布之间的差异。交叉熵损失在预测错误时会给较大的惩罚。直观理解:预测概率分布与真实概率分布之间的“距离”。
- mindspore.ops.l1_loss 或 mindspore.nn.MAELoss:MAE计算预测值与真实值之间差异的绝对值的平均,它对异常值不如MSE那么敏感。
- RMSE 是根均方误差(Root Mean Square Error),
- mindspore.ops.huber_loss 或 mindspore.nn.HuberLoss 损失结合了均方误差(MSE)和平均绝对误差(MAE)的优点,对异常值具有鲁棒性。
mindspore.ops 和 mindspore.nn 内置了很多损失函数,本小节用到的有下面两个:
- mindspore.ops.binary_cross_entropy_with_logits : 计算预测值和目标值之间的二值交叉熵损失。将输入 logits 设置为 𝑋 ,输入 labels 设置为 𝑌 ,输入 weight 设置为 𝑊 ,输出设置为 𝐿 。
- mindspore.nn.BCEWithLogitsLoss :输入经过 sigmoid 激活函数后作为预测值,该函数计算预测值和目标值之间的二值交叉熵损失。
mindspore.ops.binary_cross_entropy_with_logits(logits, label, weight=None, pos_weight=None, reduction='mean')
"""ARGS
logits (Tensor) - 输入预测值。其数据类型为float16或float32。label (Tensor) - 输入目标值,shape与 logits 相同。数据类型为float16或float32。weight (Tensor,可选) - 指定每个批次二值交叉熵的权重。支持广播,使其shape与 logits 的shape保持一致。数据类型必须为float16或float32。默认值:None , weight 是值为 1 的Tensor。pos_weight (Tensor,可选) - 指定正类的权重。是一个长度等于分类数的向量。支持广播,使其shape与 logits 的shape保持一致。数据类型必须为float16或float32。默认值:None , pos_weight 是值为 1 的Tensor。reduction (str,可选) - 指定应用于输出结果的规约计算方式,默认为 'mean', 可选参数如下。- 'none':不应用规约方法。- 'mean':计算输出元素的加权平均值。- 'sum':计算输出元素的总和。
"""
mindspore.nn.BCEWithLogitsLoss(reduction='mean', weight=None, pos_weight=None)
"""ARGS
reduction (str,可选) - 指定应用于输出结果的规约计算方式,可选 'none' 、 'mean' 、 'sum' ,默认为 'mean' 。- "none":不应用规约方法。- "mean":计算输出元素的加权平均值。- "sum":计算输出元素的总和。weight (Tensor, 可选) - 指定每个批次二值交叉熵的权重。如果不是None,将进行广播,其shape与 logits 的shape保持一致,数据类型为float16或float32。默认值: None 。pos_weight (Tensor, 可选) - 指定正样本的权重。是一个长度等于分类数的向量。如果不是None,将进行广播,其shape与 logits 的shape保持一致,数据类型必须为float16或float32。默认值: None 。
"""
计算图(Computation Graph)
计算图由节点(nodes,如执行数学运算的操作节点、变量节点)和 边(edges,如数据流、控制流)组成,是一种用于表示数学运算和数据处理流程的图形化工具,在深度学习框架中用于自动微分(即自动计算导数)。
例子:
训练深度学习模型时,首先构建计算图,用于前向传播(Forward Propagation),即从输入数据到输出结果的计算过程;在反向传播(Backward Propagation)过程中,计算图被用于自动计算梯度,这些梯度随后用于更新模型的参数。
前向传播
如下代码例子,构建了前向传播函数过程。x 为输入,y 为正确值,w 和 b 是我们需要优化的参数。
反向传播
自动微分接口 mindspore.grad 和 mindspore.value_and_grad 声称接近于数学语义。
为了优化模型参数,需要求参数对loss的导数,即 和 ,通过调用 mindspore.grad 函数,生成求导函数,用于计算给定函数的梯度或微分函数。
> 使用 grad 获得微分函数是一种函数变换,即输入为函数,输出也为函数。
mindspore.grad( fn, grad_position=0, weights=None, has_aux=False, return_ids=False)
"""ARGS
fn (Union[Cell, Function]) - 待求导的函数或网络。grad_position (Union[NoneType, int, tuple[int]]) - 指定求导输入位置的索引。若为int类型,表示对单个输入求导;若为tuple类型,表示对tuple内索引的位置求导,其中索引从0开始;若是None,表示不对输入求导,这种场景下, weights 非None。默认值: 0 。weights (Union[ParameterTuple, Parameter, list[Parameter]]) - 训练网络中需要返回梯度的网络变量。一般可通过 weights = net.trainable_params() 获取。默认值: None 。has_aux (bool) - 是否返回辅助参数的标志。若为 True , fn 输出数量必须超过一个,其中只有 fn 第一个输出参与求导,其他输出值将直接返回。默认值: False 。return_ids (bool) - 是否返回由返回的梯度和指定求导输入位置的索引或网络变量组成的tuple。若为 True ,其输出中所有的梯度值将被替换为:由该梯度和其输入的位置索引,或者用于计算该梯度的网络变量组成的tuple。默认值: False 。
"""
mindspore.value_and_grad( fn, grad_position=0, weights=None, has_aux=False, return_ids=False)
"""ARGS
fn (Union[Cell, Function]) - 待求导的函数或网络。grad_position (Union[NoneType, int, tuple[int]]) - 指定求导输入位置的索引。若为int类型,表示对单个输入求导;若为tuple类型,表示对tuple内索引的位置求导,其中索引从0开始;若是None,表示不对输入求导,这种场景下, weights 非None。默认值: 0 。weights (Union[ParameterTuple, Parameter, list[Parameter]]) - 训练网络中需要返回梯度的网络变量。一般可通过 weights = net.trainable_params() 获取。默认值: None 。has_aux (bool) - 是否返回辅助参数的标志。若为 True , fn 输出数量必须超过一个,其中只有 fn 第一个输出参与求导,其他输出值将直接返回。默认值: False 。return_ids (bool) - 是否返回由返回的梯度和指定求导输入位置的索引或网络变量组成的tuple。若为 True ,其输出中所有的梯度值将被替换为:由该梯度和其输入的位置索引,或者用于计算该梯度的网络变量组成的tuple。默认值: False 。
"""
单输出函数求导-代码例子
如下代码中,mindspore.grad 的求导索引为 (2, 3),表示 function1 函数的参数 w 和 b。
多输出函数求导-代码例子
如下图,函数存在多个输出时,求得𝑤、𝑏对应的梯度值发生了变化。
如果想要屏蔽掉函数输出 z 对梯度的影响,即仍只求参数对loss的导数,可以使用ops.stop_gradient
接口将梯度在函数输出 z 处截断。如下代码图例。
多输出函数求导--将非loss项作为辅助数据输出
Auxiliary data(辅助数据)是函数除第一个输出项外的其他输出。通常将函数的loss设置为函数的第一个输出,其他的输出即为辅助数据。 mindspore.grad 和 mindspore.value_and_grad 提供has_aux
参数,当其设置为True
时,可以自动实现前文手动添加 stop_gradient
的功能,满足返回辅助数据的同时不影响梯度计算的效果。
基于Cell网络模型反向传播-代码
使用Cell封装神经网络模型,模型参数w、b均为Cell的内部属性,此时不需要使用求导索引grad_position
对函数输入求导,将其配置为None;此时
使用 weights
参数,使用 mindspore.nn.Cell.trainable_params(recurse=True) 方法从Cell中取出可以求导的参数。
本小节代码如下。
import numpy as np
import mindspore
from mindspore import nn
from mindspore import ops
from mindspore import Tensor, Parameter# Define model
class Network(nn.Cell):def __init__(self):super().__init__()self.w = wself.b = bdef construct(self, x):z = ops.matmul(x, self.w) + self.breturn z# Define forward function
def forward_fn(x, y):z = model(x)loss = loss_fn(z, y)return lossx = ops.ones(5, mindspore.float32) # input tensor
y = ops.zeros(3, mindspore.float32) # expected output
w = Parameter(Tensor(np.random.randn(5, 3), mindspore.float32), name='w') # weight
b = Parameter(Tensor(np.random.randn(3,), mindspore.float32), name='b') # bias# Instantiate model
model = Network()
# Instantiate loss function
loss_fn = nn.BCEWithLogitsLoss()grad_fn = mindspore.value_and_grad(forward_fn, None, weights=model.trainable_params())loss, grads = grad_fn(x, y)
print(grads)