之前用的是使用迭代进行直接的求解
但是深度学习最常用的方法是:根据样本学习
- 收集要解决问题的事件样本(一个x对应一个y【x多个,y一个】)
- 平方根的样本是比较好收集的,比如:0.1的样本就是0.01;0.2的样本就是0.04,等等
- 通过样本建立网络,输出作为平方根(更直接,更适应样本)
之间的解法是求解 a r g m i n f ( x ) argminf(x) argminf(x)
目前的解法是求解 a r g m i n f ( x , p ) argminf(x,p) argminf(x,p)
求的值是p,而不是x
p就是要优化的东西
通过样本来查找规律,然后预测平方根
代码实现如下
- 定义主方法类
if __name__ == "__main__":
app = SqrtApp()
ys = np.array([e for e in range(-100, 100)]) / 100
xs = np.square(ys)
app.train(xs, ys)
app.close()
pl.plot(xs, ys)
xs = np.random.uniform(0,2,[400])
ys = app.sqrt(xs)
pl.plot(xs, ys)
app.close()
- 定义开平方的类:SqrtApp(框架如下)
class SqrtApp:
def __init__(self):
pass
def train(self, xs, ys, lr = 0.01, epoches = 2000):
pass
def sqrt(self,n):
pass
def close(self):
pass
- 定义输入和输出的值
def __init__(self):
# 样本的数量不确定用-1来表示,长度为1个:[-1, 1]。但是在TensorFlow中[-1]会有问题,一般使用None表示
x = tf.placeholder(tf.float32, [None], 'x') # x指求平方根的数,而不是需要放进去平方根的变量
self.x = x # 对x进行保存
x = tf.reshape(x, [-1, 1]) # 将输入的一维转换成向量
# 进行全连接操作(利用多项式来和矩阵进行相乘)多项式是一个系数矩阵
w = tf.get_variable('w', [1 ,200], tf.float32) # 定义一个系数矩阵,矩阵的名字为w。用参数w来保存平方根的规律,需要优化的也是w这个参数
b = tf.get_variable('b', [200], tf.float32)
x = tf.matmul(x,w) + b # 全连接的最终结果,其中b是一个偏值(多项式变换的一个常规的做法)
# x 得到的形状是:[-1, 200], w 和 b是可以相乘的
# 最后使用激活函数
x = tf.relu(x) # relu(x) === maximum(x,0) 后面我会解释为啥用激活函数
# 再定义一对矩阵和偏值
w = tf.get_variable('w2', [200,1], tf.float32) # 因为获得的x是[-1,200],所以w的维度应该是[200,1]
b = tf.get_variable('b2', [200], tf.float32)
self.y_predict = tf.matmul(x, w) + b # [-1 , 1] # 为最终的结果进行保存(我们所希望的平方根)
# 这个y是你的预测值,而不是输入的样本x的值
self.y_predict = tf.reshape(self.y_predict, [-1]) # 将二维矩阵转换成一维的向量
# 把输入的标签也传入进来
self.y = tf.placeholder(tf.float32, [None], 'y')
loss = tf.reduce_mean(tf.square(self.y - self.y_predict)) # 求损失函数
self.lr = tf.placeholder(tf.float32, [None], 'lr') # lr s
opt = tf.train.AdanOptimizer(lr) # 定义梯度下降优化器
self.train_op = opt.minmize(loss) # 训练操作(控制输入输出的优化操作)
self.session = tf.Session()
self.session.run(tf.global_variables_initalizer()) # 初始化方法中的所有变量
过程如下:
模型优化主要就是优化:w、b、w2、b2这四个参数
为了达到这目的,这个模型需要进行两个阶段使用
- 第一个是训练模型
- 第二个是使用模型
训练多次,使用就一次,所以我们需要有一个训练操作
def train(self, xs, ys, lr = 0.01, epoches = 2000):
for _ in range(epoches):
self.session.run(self.train_op,{self.x:xs, self.y:y, self.lr:lr}) # 对三个参数进行优化
正常来讲,lr和epoches是放在sqrt方法中的,就是因为需要分开使用所以将参数放在train函数中了
张量全部可以通过self进行获取
三个输入张量:x、y、lr
一个输出张量:y_predict
一个训练张量:train_op
def close(self):
self.session.close()
def sqrt(self,n):
ys = self.session.run(self.y_predict,{self.x:xs}) # 运行y_predict
return ys
运行的结果如下:
题外话:为什么session在构造函数中定义,而不是在train中定义的?
如果定义在train中,如果train结束了,那么session也就结束了,变量的加载也就结束了。
在一个方法里面,不管是成员方法还是全局方法,原则上,代码的数量应该少。所以我们可以定义一个tensors类来包含构造函数中的方法。