这次来做一个小项目,算是tensorflow入门级别的实践。手头有一份北京全年气温的数据,现在通过训练模型拟合出一条全年气温的曲线,可用于对北京某个日期下气温的预测。
数据获取与加工
从kaggle下载了北京PM2.5的全年数据,数据表中包含了全年气温,数据文件是CSV格式(下载地址:http://www.digeek.tech/download/PM25.csv),下面是数据文件的格式与内容:
表格中每一行表示北京一年中某一天凌晨0点的数据,一共365条数据,每天一条,本篇中只会用到温度数据。
下面是数据获取的代码部分:
# 引入tensorflow、numpy和matplotlib库
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# 获取数据
data = np.genfromtxt('/Users/Bruce/Desktop/PM25.csv', dtype=float, delimiter=',', skip_header=1)
x_data = np.array([x[0] for x in data])[:, np.newaxis]
y_data = np.array([y[13] for y in data])[:, np.newaxis]
# 绘图,绘出训练数据
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x_data, y_data)
plt.show()
print(x_data)
print("----------------------")
print(y_data)
为简单起见,x_data只获取序号,y_data则表示每天的数据,需要注意的是,获取数据后需要转格式成np.array,并且转换成 [n, 1] 矩阵。
通过matplotlib.pyplot库将数据绘制出来,如下图所示:
横坐标是日期,纵坐标是温度,在开始建模之前,还需要对数据做一些处理,因为x_data的范围是1-365,这个范围太大了,在机器学习过程中可能会遇到梯度爆炸,即无法拟合的情况,所以需要将x_data映射到0至1的范围内,这一过程称为归一化,公式是这样的:
下面将代码做了修改:
# 引入tensorflow、numpy和matplotlib库
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# 获取数据
data = np.genfromtxt('/Users/Bruce/Desktop/PM25.csv', dtype=float, delimiter=',', skip_header=1)
x_ = np.array([x[0] for x in data])[:, np.newaxis]
# 数据归一化
amin, amax = x_.min(), x_.max()
# 求最大最小值
x_data = (x_ - amin)/(amax - amin)
y_data = np.array([y[13] for y in data])[:, np.newaxis]
# 绘图,绘出训练数据
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x_data, y_data)
plt.show()
print(x_data)
print("----------------------")
print(y_data)
模型结构
模型分为输入层、隐藏层和输出层。
输入层就是现有的训练数据,日期与气温,这是 [n, 1] 的矩阵结构。输出层即通过机器学习或的预测值。在输入层和输出层之前还设计了1层隐藏层,隐藏层一共包含200个节点,大概的样子是这样的。
下面是代码实现:
#输入层
xs = tf.placeholder(tf.float32, [None, 1]) #占位符,None表示n*1维矩阵
ys = tf.placeholder(tf.float32, [None, 1]) #占位符,None表示n*1维矩阵
#隐层(200个神经元)
W1 = tf.Variable(tf.random_normal([1,200])) #权重,1*200的矩阵,并用符合正态分布的随机数填充
b1 = tf.Variable(tf.zeros([1,200]) + 0.1) #偏置,1*200的矩阵,使用0.1填充
Wx_plus_b1 = tf.matmul(xs,W1) + b1 #矩阵xs和W1相乘,然后加上偏置
output1 = tf.nn.sigmoid(Wx_plus_b1) #激活函数使用tf.nn.sigmoid
#输出层
W2 = tf.Variable(tf.random_normal([200,1])) #权重,200*1的矩阵,并用符合正态分布的随机数填充
b2 = tf.Variable(tf.zeros([1])+0.1) # 偏置,使用0.1填充
Wx_plus_b2 = tf.matmul(output1,W2) + b2
output2 = Wx_plus_b2 # 输出层不使用激活函数
输入层使用了placeholder;
输出层和隐藏层很类似,但是没有加激活函数,另外输出层的节点数量是1,实际会输出一个一维矩阵。
损失函数与训练算法
通过隐藏层和输出层的计算,会得到一个一维矩阵,矩阵中的元素是通过计算得出的每天对应的气温,这个计算值与训练样本中的气温值的差距就是损失,在计算损失时,使用了偏差平方求和,再取平均值的方式,如下:
#损失
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-output2),reduction_indices=[1])) #在第一维上,偏差平方后求和,再求平均值,来计算损失
机器学习的目的就是使损失降低,这里使用了梯度下降的方式来降低损失,关于梯度下降算法这里不做说明,基本逻辑是通过计算损失,去修改模型中的权重和偏置的值(反向传播),并计算新的损失,直至损失降低到可接受的范围内,这样就得到了模型的全部权重和偏置,即本篇中拟合曲线的实现公式。
train_step = tf.train.GradientDescentOptimizer(0.005).minimize(loss) # 使用梯度下降法,设置步长0.005,来最小化损失
在设置梯度下降算法时,需要人工设置学习率(步长),一般数值都比较小,如果发现无法拟合,可以调小学习率,如果拟合速度过慢,可以调大学习率。
完整代码
下面是完整的实现代码
# 引入tensorflow、numpy和matplotlib库
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
# 获取数据
data = np.genfromtxt('/Users/Bruce/Desktop/PM25.csv', dtype=float, delimiter=',', skip_header=1)
x_ = np.array([x[0] for x in data])[:, np.newaxis]
# 数据归一化
amin, amax = x_.min(), x_.max()
# 求最大最小值
x_data = (x_ - amin)/(amax - amin)
y_data = np.array([y[13] for y in data])[:, np.newaxis]
# 绘图,绘出训练数据
fig = plt.figure()
ax = fig.add_subplot(1,1,1)
ax.scatter(x_data, y_data)
plt.ion()plt.show()
#输入层
xs = tf.placeholder(tf.float32, [None, 1]) #占位符,None表示n*1维矩阵
ys = tf.placeholder(tf.float32, [None, 1]) #占位符,None表示n*1维矩阵
#隐层(200个神经元)
W1 = tf.Variable(tf.random_normal([1,200])) #权重,1*200的矩阵,并用符合正态分布的随机数填充
b1 = tf.Variable(tf.zeros([1,200]) + 0.1) #偏置,1*200的矩阵,使用0.1填充
Wx_plus_b1 = tf.matmul(xs,W1) + b1 #矩阵xs和W1相乘,然后加上偏置
output1 = tf.nn.sigmoid(Wx_plus_b1) #激活函数使用tf.nn.sigmoid
#输出层
W2 = tf.Variable(tf.random_normal([200,1])) #权重,200*1的矩阵,并用符合正态分布的随机数填充
b2 = tf.Variable(tf.zeros([1])+0.1) # 偏置,使用0.1填充
Wx_plus_b2 = tf.matmul(output1,W2) + b2
output2 = Wx_plus_b2 # 输出层不使用激活函数
#损失
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys-output2),reduction_indices=[1])) #在第一维上,偏差平方后求和,再求平均值,来计算损失
train_step = tf.train.GradientDescentOptimizer(0.005).minimize(loss) # 使用梯度下降法,设置步长0.005,来最小化损失
#初始化
init = tf.global_variables_initializer() #初始化所有变量
sess = tf.Session()
sess.run(init) #变量初始化
#训练
for i in range(5001): #训练10000次
_,loss_value = sess.run([train_step,loss],feed_dict=) #进行梯度下降运算,并计算每一步的损失
if(i%20==0):
print("第%d步,loss_value = %f" % (i,loss_value)) # 每50步输出一次损失
try:
ax.lines.remove(lines[0]) # 在每一次绘图之前先讲上一次绘图删除
except Exception:
pass
lines = ax.plot(x_data, sess.run(output2, feed_dict=), 'r-') plt.pause(0.1)
sess.close()
训练循环总共设置了5001步,每20步打印出当前的损失数值,并且绘制出拟合的曲线样式,运行起来会看到动画的拟合过程,比较直观。
数字极客
公众号ID:digital-geek
关注
领取专属 10元无门槛券
私享最新 技术干货