北大MOOC——TF2.0笔记
以下是我的听课笔记,供以后回忆(大多内容来自ppt)
一.神经网络优化
1.常用函数讲解
np.mgrid函数:
import numpy as np
import tensorflow as tf
# 生成等间隔数值点
x,y= np.mgrid[1:2:0.5,2:3.5:0.5]
# 将x, y拉直,并合并配对为二维张量,生成二维坐标点
grid = np.c_[x.ravel(), y.ravel()]
print("x:\n", x)
print("y:\n", y)
print("x.ravel():\n", x.ravel())
print("y.ravel():\n", y.ravel())
print('grid:\n', grid)
输出:
此例子[1:2)以0.5为间隔,有1,1.5,有两个元素
[2:3.5)以0.5为间隔,有2,2.5,3,有三个元素
则输出的x,y的格式为2行三列
(x中每一列为一个完整的数列,y中每一行为一个完整的数列)
2.神经网络(NN)复杂度
NN的层数:只统计具有运算能力的层,即隐藏层+输出层(输入层不具有计算能力,因此不纳入统计)
隐藏层:输入层与输出层之间的所有层都叫隐藏层。
3.衰减学习率
import tensorflow as tf
w = tf.Variable(tf.constant(5, dtype=tf.float32))
epoch = 40
LR_BASE = 0.2 # 最初学习率
LR_DECAY = 0.99 # 学习率衰减率
LR_STEP = 1 # 喂入多少轮BATCH_SIZE后,更新一次学习率
for epoch in range(epoch): # for epoch 定义顶层循环,表示对数据集循环epoch次,此例数据集数据仅有1个w,初始化时候constant赋值为5,循环100次迭代。
lr = LR_BASE * LR_DECAY ** (epoch / LR_STEP)
with tf.GradientTape() as tape: # with结构到grads框起了梯度的计算过程。
loss = tf.square(w + 1)
grads = tape.gradient(loss, w) # .gradient函数告知谁对谁求导
w.assign_sub(lr * grads) # .assign_sub 对变量做自减 即:w -= lr*grads 即 w = w - lr*grads
print("After %s epoch,w is %f,loss is %f,lr is %f" % (epoch, w.numpy(), loss, lr))
输出:
4.激活函数
Sigmoid激活函数:
把输入值变为[0,1]之间的数值输出。若输入是绝对值很大的复数,则输出为0;若输入是很大的正数,则输出是1。
由于深层神经网络更新参数时,需要从输入层到输出层逐层链式求导,Sigmoid函数的导是[0,0.25]的小数,多次乘法运算后,结果趋近于0。产生梯度消失,使得参数无法更新。因此Sigmoid激活函数现在并不常用。
Tanh激活函数:
Relu激活函数:
缺点:若送入激活函数的输入值是负数,激活函数输出是0,反向传播得到的梯度是0,导致参数无法更新,造成神经元死亡
实际情况中还是使用Relu较多。
5.损失函数
均方误差MSE:
自定义损失函数:
交叉熵损失函数SE:
import tensorflow as tf
import numpy as np
SEED = 23455
COST = 1 #成本
PROFIT = 99 #利润
#x(32,2) w1(2,1) 预测值y= matmul(x, w1)是(32,1)32行1列的
rdm = np.random.RandomState(SEED)
x = rdm.rand(32, 2)
y_ = [[x1 + x2 + (rdm.rand() / 10.0 - 0.05)] for (x1, x2) in x] # 生成噪声[0,1)/10=[0,0.1); [0,0.1)-0.05=[-0.05,0.05)
x = tf.cast(x, dtype=tf.float32)
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) #y是预测的值
loss = tf.reduce_sum(tf.where(tf.greater(y, y_), (y - y_) * COST, (y_ - y) * PROFIT)) #32组的差之和
grads = tape.gradient(loss, w1) #先用loss对w1求导,之后再将w1的值带入
#loss是关于w1的函数???
w1.assign_sub(lr * grads)
if epoch % 500 == 0:
print("After %d training steps,w1 is " % (epoch))
print(w1.numpy(), "\n")
print("y_",y_) #y_是列表形式
print("y", y)
print("loss", loss)
print("grads", grads)
print("Final w1 is: ", w1.numpy())
# 自定义损失函数
# 酸奶成本1元, 酸奶利润99元
# 成本很低,利润很高,人们希望多预测些,生成模型系数大于1,往多了预测
对于代码我很好奇,loss不是关于w1的函数呀,loss对w1求偏导的操作是什么呢?下图是其他博主的解答:
欠拟合:是对现有数据集学习的不够彻底
过拟合:是模型对当前数据拟合的太好了,但对从未见过的新数据不能做出正确的判断。
数据噪声:数据中存在的错误或异常的数据,对模型有误导作用的数据。
过拟合。就是拟合函数顾忌的点太多,函数在小范围内波动很大。这就代表着函数在小范围内的斜率很大(即导数的绝对值很大),由于自变量值可大可小,所以只有系数足够大,才能保证导数值很大。而正则化是通过约束参数的范数使其不要太大,所以可以在一定程度上减少过拟合情况。
正则化的目的是限制参数过多或者过大,避免模型更加复杂。