自定义损失函数 和 多输入参数的 线性拟合
本文将基于 MindSpore 搭建一个 拟合 y ′ + 1 = 1 ∗ x 1 + 2 ∗ x 2 = y y' + 1 = 1 * x_1 + 2 * x_2 = y y′+1=1∗x1+2∗x2=y 函数的算法。其中 y y y 是神经网络正向传播应该输出的值,也就是真正的目标值。而 y ′ y' y′ 是假的目标值,需要进行 + 1 +1 +1 操作才能得到真的目标值。
也就是要自定义损失函数,在损失函数中,需要对输入的临时目标值进行处理,也就是进行 + 1 +1 +1 操作,才得到真正的目标值。
用假的目标值训练网络,最终,网络的输出值要接近真正的目标值。
完整代码 和 注释 如下:
import numpy as np
from mindspore import dataset as ds
from mindspore.common.initializer import Normal
from mindspore import Model, Tensor, context, nn, set_seed, ops
import mindspore as ms
context.set_context(mode=context.GRAPH_MODE, device_target="CPU") # 设置静态图模式,CPU 支持此模式
set_seed(1)
class add_Loss(nn.Cell): # 自定义损失函数,参考链接:
# https://www.mindspore.cn/docs/programming_guide/zh-CN/r1.6/loss.html#%E5%AE%9A%E4%B9%89%E6%8D%9F%E5%A4%B1%E5%87%BD%E6%95%B0
def __init__(self):
super(add_Loss, self).__init__()
self.add = ops.Add()
self.square = ops.Square()
self.reduce_mean = ops.ReduceMean()
def construct(self, x, y_): # 第一个参数 x 为神经网络前向输出值,第二个参数为 假的目标值。
y = self.add(y_, 1.) # 注意, 此处的运算操并非必须为 ops 操作,才能自动计算梯度。正常的计算也可以,比如 下面注释掉的 + 和 **2。
loss = self.square(x - y)
# y = y_ + 1.
# loss = (x - y)**2
loss = self.reduce_mean(loss)
return loss
def get_data(num, w_1=1.0, w_2=2.0):
for _ in range(num):
x_1 = np.random.uniform(-10.0, 10.0)
x_2 = np.random.uniform(-10.0, 10.0)
y_ = x_1 * w_1 + x_2 * w_2 - 1
yield np.array([x_1, x_2]).astype(np.float32), np.array([y_]).astype(np.float32) # MindSpore 默认的计算精度为 Float32,所以也要匹配。
# 用 yield 函数生成可迭代的生成器,当 num 很大时,可很有效的减小内存占用
def create_dataset(num_data, batch_size=16, repeat_size=1):
input_data = ds.GeneratorDataset(list(get_data(num_data)), column_names=['data', 'label'])
# GeneratorDataset 将生成的数据转换为 MindSpore 的数据集,并且将生成的数据的 x,y 值存入到 data 和 label 的数组中。
input_data = input_data.batch(batch_size)
# 将 batch_size 个数据组合成一个 batch,则一共有 num_data/batch_size 个 batch。
input_data = input_data.repeat(repeat_size) # 将数据集数量倍增。非必须步骤。
return input_data
data_number = 1600
batch_number = 16
repeat_number = 1
ds_train = create_dataset(data_number, batch_size=batch_number, repeat_size=repeat_number)
class LinearNet(nn.Cell):
def __init__(self):
super(LinearNet, self).__init__()
self.fc = nn.Dense(2, 1) # 全连接层
def construct(self, x): # 必须要有这个函数,MindSpore 对 construct 接口有一定约束
x = self.fc(x)
return x
net = LinearNet()
net_loss = add_Loss() # 采用自定义的损失函数
opt = nn.Momentum(net.trainable_params(), learning_rate=0.005, momentum=0.9) # 优化器
model = Model(net, net_loss, opt)
model.train(1, ds_train, dataset_sink_mode=False)
# 测试一下
print(model.predict(Tensor([[1., 2.]], dtype=ms.float32))) # 最终输出结果为 [[4.996882]] 恰为想要的 1*1 + 2*2 = 5 的结果
[[4.996882]]