酸奶日销量y(预测值) x1,x2是两个影响日销量的因素
【现在需要探讨y与x1和x2的关系】
损失函数:使用mse-均方误差损失函数
tf表达式为:lose_mse=tf.reduce_mean(tf.square(y_-y))
(y_真实值,y预测值),损失函数就是计算真实值与预测值之间的距离,所以越小越好
建模前应当预先采集的数据有
每日的x1,x2和当日真实销量y_(真实值)
【数据集准备】
为了方便实验
随机自动生成一个包含两个因素x1,x2的数据集x(x越大越好)
和一个表示真实销量的数据集y_
我们暂且拟定y_=x1+x2(也就是两个因素的系数都为1,同样重要)
为了更接近真实情况,再架上一个随机噪声(-0.05~+0.05)
已知答案——最佳情况是: 产量=销量
(生产多了会赔钱,生产少了少挣钱)
import tensorflow as tf
import numpy as np
SEED=23455
#rdm函数,指定随机种子23455————生成[0,1)之间的随机数
rdm=np.random.RandomState(seed=SEED)
# 生成包含两个因素x1和x2的随机数据集x(32组)——32*2
# 生成表示真实销量的随机数据集y_(32*1)
# 暂定(y_=x1+x2+随机噪声)
x=rdm.rand(32,2)
y_=[[x1+x2+(rdm.rand()/10.0-0.05) ] for (x1,x2) in x]
x=tf.cast(x,dtype=tf.float32)
#随机初始化可更新的变量w1,2*1
w1=tf.Variable(tf.random.normal([2,1],stddev=1,seed=1))
epoch=10000
lr=0.002
for epoch in range(epoch):
with tf.GradientTape() as tape:
#计算预测值
y=tf.matmul(x,w1)
#计算均方误差
loss_mse=tf.reduce_mean(tf.square(y_-y))
#梯度更新参数
grads=tape.gradient(loss_mse,w1)
w1.assign_sub(lr*grads)
#每训练500轮输出一次w1两个参数
if epoch%500==0:
print("经过%d轮训练,w1的值为"%(epoch))
print(w1.numpy(),"\n")
print("最终w1的值为",w1.numpy())
以上用均方误差作为损失函数,默认是认为销量预测多了或者少了,损失是一样的,所以从头到尾这个loss函数都没有变化。然而真实情况是,预测多了,会损失成本COST,预测少了,会损失利润PROFIT,而利润和成本往往不相等,这种情况下使用均方误差计算loss,无法达到利益最大化。
自定义损失函数
将loss函数定义为一个分段函数
每一轮比较预测值和真实值决定loss值
当预测值y小于真实值y_的时候,预测少了,损失利润
得出一个损失值PROFIT(y_ - y)
当预测值y大于等于真实值y_的时候,预测多了,损失成本
得出一个损失值COST(y - y_)
最后将所有损失值求和
实现:就是一个条件判断的三段式,前面加一个sum求和
loss_zdy=tf.reduce_sum(tf.where(tf.greater(y,y_),COST*(y-y_),PROFIT*(y_-y))
假设酸奶成本1元,酸奶利润99元
预测少了损失利润99元,预测多了损失成本1元
预测少了损失更大,所以希望模型,也就是最终预测的函数
尽量往销量多的方向预测
import tensorflow as tf
import numpy as np
SEED=23455
COST=1
PROFIT=99
#重命名函数rdm——生成[0,1)之间的随机数
rdm=np.random.RandomState(seed=SEED)
#生成包含两个因素x1和x2的随机数据集x(32组)
#生成表示真实销量的随机数据集y_
#(y_=x1+x2+随机噪声)
x=rdm.rand(32,2)
y_=[[x1+x2+(rdm.rand()/10.0-0.05) ] for (x1,x2) in x]
x=tf.cast(x,dtype=tf.float32)
#随机初始化可更新的变量w1,两行一列
w1=tf.Variable(tf.random.normal([2,1],stddev=1,seed=1))
epoch=10000
lr=0.002
for epoch in range(epoch):
with tf.GradientTape() as tape:
#计算预测值
y=tf.matmul(x,w1)
#损失函数——自定义分段函数
loss=tf.reduce_sum(tf.where(tf.greater(y,y_),(y-y_)*COST,(y_-y)*PROFIT))
#梯度更新参数
grads=tape.gradient(loss,w1)
w1.assign_sub(lr*grads)
#每训练20轮输出一次w1两个参数
if epoch%500==0:
print("经过%d轮训练,w1的值为"%(epoch))
print(w1.numpy(),"\n")
print("最终w1的值为",w1.numpy())