TensorFlow™是一个基于数据流编程(dataflow programming)的符号数学系统,被广泛应用于各类机器学习(machine learning)算法的编程实现,其前身是谷歌的神经网络算法库DistBelief [1] 。
它是现在最流行的机器学习框架,甚至在此领域大有要垄断的态势。
TensorFlow™ 是一个采用数据流图(data flow graphs),用于数值计算的开源软件库。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor)。它灵活的架构让你可以在多种平台上展开计算,例如台式计算机中的一个或多个CPU(或GPU),服务器,移动设备等等。TensorFlow 最初由Google大脑小组(隶属于Google机器智能研究机构)的研究员和工程师们开发出来,用于机器学习和深度神经网络方面的研究,但这个系统的通用性使其也可广泛用于其他计算领域。
数据流图用“结点”(nodes)和“线”(edges)的有向图来描述数学计算。“节点” 一般用来表示施加的数学操作,但也可以表示数据输入(feed in)的起点/输出(push out)的终点,或者是读取/写入持久变量(persistent variable)的终点。“线”表示“节点”之间的输入/输出关系。这些数据“线”可以输运“size可动态调整”的多维数据数组,即“张量”(tensor)。张量从图中流过的直观图像是这个工具取名为“Tensorflow”的原因。一旦输入端的所有张量准备好,节点将被分配到各种计算设备完成异步并行地执行运算。
这个安装是最拿人的了,GPU版本的性能要比CPU版本的好上很多,但是因为要配置显卡,所以更加难安装,(另外笔者的电脑GPU是GTX-1050TI装不了GPU版本),而入门的话CPU就够了,此处只简单的记录一下如何安装CPU版本。
配置:
Win10 ; python3.6 ;tensorflow 1.14.0
说明:
步骤:
再次试了用anaconda进行安装,换用了清华大学的源,真的快了不是一点半点
安装anaconda:
按步骤安装就行,只注意要勾选加入路径,和默认用anaconda的python解释器,安装完成后在pycharm中解释器的路径在anaconda文件中的Script文件中找python.exe,pycharm也就能用了。
换装清华的源
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/
conda config --set show_channel_urls yes
之后安装就可以用conda了,conda的操作和pip几乎一摸一样
pip list / conda list
pip install 【package】== version / conda install 【package】= version
pip install 【package】 --upgrade / conda update 【package】
我们在安装conda的时候默认创建了一个base环境,使用的是anaconda的默认解释器(我的是3.7),但为了防止包混乱,我们可以为tensorflow创建一个独立的环境。
conda create --name tf python=3.7 /创建一个名为tf的虚拟环境,里面安装的解释器为python3.7版本
C:\Users\12521>conda env list /此时在看看包含的env中除了base还有个tf
# conda environments:
#
base * C:\Users\12521\Anaconda3
tf C:\Users\12521\Anaconda3\envs\tf
C:\Users\12521>activate tf /激活tf
(tf) C:\Users\12521> /成功
- conda create --name [env-name] # 建立名为[env-name]的Conda虚拟环境
- conda activate [env-name] # 进入名为[env-name]的Conda虚拟环境
- conda deactivate # 退出当前的Conda虚拟环境
- conda env remove --name [env-name] # 删除名为[env-name]的Conda虚拟环境
- conda env list # 列出所有Conda虚拟环境
pip install tensorflow==2.0.0-beta0
/ 安装完成后import还是不能用
pip install numpy == 1.16
/numpy版本太高,安装低一点的就好了
>>> random_float = tf.random.uniform(shape=())
>>> print(random_float)
tf.Tensor(0.9904655, shape=(), dtype=float32)
>>>random_float = tf.random.uniform(shape=(2,3))
>>> print(random_float)
tf.Tensor(
[[0.7376052 0.25581563 0.1726948 ]
[0.74306595 0.18850088 0.2021966 ]], shape=(2, 3), dtype=float32)
//一般生成方式
>>> vector = tf.constant([[1,2],[3,4]])
>>> print(vector)
tf.Tensor(
[[1 2]
[3 4]], shape=(2, 2), dtype=int32)
//zeros
>>> zero_vector = tf.zeros(shape=(2))
>>> print(zero_vector)
tf.Tensor([0. 0.], shape=(2,), dtype=float32)
>>> zero_vector = tf.zeros(shape=(2,3))
>>> print(zero_vector)
tf.Tensor(
[[0. 0. 0.]
[0. 0. 0.]], shape=(2, 3), dtype=float32)
//ones
>>> one_vector = tf.ones(shape=(2))
>>> print(one_vector)
tf.Tensor([1. 1.], shape=(2,), dtype=float32)
>>> one_vector = tf.ones(shape=(2,2))
>>> print(one_vector)
tf.Tensor(
[[1. 1.]
[1. 1.]], shape=(2, 2), dtype=float32)
//eye生成单位向量,此处就没有shape=()了了了
>>> eye_vector = tf.eye(3)
>>> eye_vector
>>> zero_vector = tf.zeros(shape=(2,3,4))
>>> print(zero_vector)
tf.Tensor(
[[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]
[[0. 0. 0. 0.]
[0. 0. 0. 0.]
[0. 0. 0. 0.]]], shape=(2, 3, 4), dtype=float32)
>>> one_vector = tf.ones(shape=(2,3,4))
>>> print(one_vector)
tf.Tensor(
[[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]
[[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]]], shape=(2, 3, 4), dtype=float32)
········
//上代码
>>> vector = tf.constant([[1,2],[3,4]])
//形状
>>> vector.shape()
Traceback (most recent call last):
File "", line 1, in
TypeError: 'TensorShape' object is not callable
>>> vector.shape
TensorShape([2, 2])
//数据类型
>>> vector.dtype
tf.int32
>>> vector = tf.constant([[1,2],[3,4]],dtype=tf.float32) //在定义张量的时候可以
>>> print(vector)
tf.Tensor(
[[1. 2.]
[3. 4.]], shape=(2, 2), dtype=float32)
//以numpy方法获得
>>> A = vector.numpy
>>> print(A)
>
>>> print(vector)
tf.Tensor(
[[1 2]
[3 4]], shape=(2, 2), dtype=int32)
>>> type(A)
>>> type(vector)
/张量的 numpy() 方法是将张量的值转换为一个NumPy数组。
>>> B = tf.ones(shape=(2,3)) //默认生成的数据类型一般是float32
>>> C = tf.ones(shape=(2,3))
>>> tf.add(B,C) //shape相同,相加成功
>>> B = tf.ones(shape=(2,2))
>>> tf.add(B,C) //改变B的shape,add失败
Traceback (most recent call last):
File "", line 1, in
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 392, in add
_six.raise_from(_core._status_to_exception(e.code, message), None)
File "", line 3, in raise_from
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2,2] vs. [2,3] [Op:Add]
>>> A = tf.constant([[1,2],[3,4]])
>>> A
>>> B
>>> tf.add(A,B) //A与B的shape相同,但是dtype不同,所以就失败聊
Traceback (most recent call last):
File "", line 1, in
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 392, in add
_six.raise_from(_core._status_to_exception(e.code, message), None)
File "", line 3, in raise_from
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute Add as input #1(zero-based) was expected to be a int32 tensor but is a float tensor [Op:Add]
//先来个简单的
>>> A = tf.constant([[1,2],[3,4]])
>>> B = tf.constant([[5,6,7],[8,9,10]])
>>> A //创建一个2*2的向量A
>>> B //创建一个2*3的向量B
>>> tf.matmul(A,B) //进行矩阵A与B之间的乘法运算
//从此例子入手,矩阵的乘法法则必须满足【矩阵A的列数必须与矩阵B的行数相同】。
//生成的的矩阵C的shape是 【A的row】*【B的column】
//具体进行的乘法运算是【A的第x行】*【B的第y列】得到矩阵C的(x,y)位置的元素
//emmm~至少目测是这样子的,有错误以后学了就知道了
//numpy存在广播机制,不知道tensorflow有没有
//上代码
>>> A
>>> B
>>> C
>>> tf.add(A,B)
>>> tf.add(A,C)
>>> tf.add(B,C)
Traceback (most recent call last):
File "", line 1, in
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\ops\gen_math_ops.py", line 392, in add
_six.raise_from(_core._status_to_exception(e.code, message), None)
File "", line 3, in raise_from
tensorflow.python.framework.errors_impl.InvalidArgumentError: Incompatible shapes: [2,3] vs. [2,2] [Op‘
//事实证明,tensorflow同样存在广播机制
PS:顺便把之前弄的稀里糊涂的广播机制也搞明白了,嘿嘿嘿
//上代码用向量A和C验证
>>> A
>>> C
>>> D //向量D是对照着C用1将向量A补全到与C的shape相同(用1补前面)
>>> tf.add(A,C)
>>> tf.add(D,C) //经过验证成立
此处以y=x^2为例
>>> x1 = tf.Variable(tf.random.uniform(shape=())) //生成随机数标量下x1
>>> x1
>>> x2 = tf.Variable(3) //生成标量x2==3
>>> x2
>>> x3 = tf.Variable(3,name='bianliang3') //生成标量x3==3,并且命名为bianliang3
>>> x3
>>> x4 = tf.Variable(tf.constant([[1,2],[3,4]])) //生成向量x4
>>> x4
with tf.GradientTape() as tape:
tape.watch([w])
y = f([w])
y_grad = tape.gradient(y, [w])
//先来个简单的标量求导
//实例代码:
>>> x2 = tf.Variable(3)
>>> with tf.GradientTape() as tape:
... tape.watch(x2)
... y = tf.square(x2)
...
WARNING: Logging before flag parsing goes to stderr.
W0815 07:57:30.611359 10928 backprop.py:842] The dtype of the watched tensor must be
floating (e.g. tf.float32), got tf.int32 //不能用int32?
>>> x = tf.Variable(3.) //试试float32
>>> x
>>> with tf.GradientTape() as tape:
... tape.watch(x)
... y = tf.square(x)
...
>>> y_grad = tape.gradient(y,x) //it does work!
>>> print(y,y_grad)
tf.Tensor(9.0, shape=(), dtype=float32) tf.Tensor(6.0, shape=(), dtype=float32)
//事实上在机器学习中,只有很少且在很简单的问题上才会对标量进行求导,求导更多的应用场景
是【向量->标量】【向量->向量】
//实例问题,求简单线性回归函数的 Cost Function
//问题解析:
多变量线性回归问题模型 : y = (w1)*(x1) +(w2)*(x2)+...+b
Cost Function:0.5 * Sigma[1~n] {y - y(实际值)}^2
偏导值:d【Cost Function{w,b}】/d【w】 //即Cost Function对变量的偏导数
//上代码
>>> x = tf.constant([[1.,2.],[3.,4.]])
>>> y = tf.constant([[1],[2]])
>>> w = tf.Variable([[1.],[2.]])
>>> w //w是变量,需要用tf.Varible初始化
>>> b=1 //b是Bias,一般是1,不会变,设为常量应该没毛病,应该吧。。
>>> with tf.GradientTape() as tape:
... CF = 1/2*tf.reduce_sum(tf.square(tf.matmul(x,w)+b-y))
...
Traceback (most recent call last):
File "", line 2, in
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\ops\math_op
s.py", line 884, in binary_op_wrapper
return func(x, y, name=name)
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\ops\gen_mat
h_ops.py", line 11571, in sub
_six.raise_from(_core._status_to_exception(e.code, message), None)
File "", line 3, in raise_from
tensorflow.python.framework.errors_impl.InvalidArgumentError: cannot compute Sub as inp
ut #1(zero-based) was expected to be a float tensor but is a int32 tensor [Op:Sub] name
: sub/ //日常翻车。。不慌。看来又是dtype弄差了。
>>> y = tf.constant([[1.],[2.]])
>>> with tf.GradientTape() as tape: //果然,重置y的dtype==float32就欧了
... CF = 1/2*tf.reduce_sum(tf.square(tf.matmul(x,w)+b-y))
...
>>> w_grad = tape.gradient(CF,w)
>>> print(CF,w_grad)
tf.Tensor(62.5, shape=(), dtype=float32) tf.Tensor(
[[35.]
[50.]], shape=(2, 1), dtype=float32)
>>> print(CF.numpy(),w_grad.numpy()) //用numpy的形式更加直观打印出结果
62.5 [[35.]
[50.]]
//分析结果很容易的得出结论,对应于w=[1,2]^T(转置),b=1的情况下, Cost Function==62.5,
d【Cost Function{w,b}】/d【w】== [35.,50.]^T
//对于b还是不是很放心。
>>> y = tf.constant([[1.],[2.]])
>>> x = tf.constant([[1.,2.],[3.,4.]])
>>> w = tf.Variable([[1.],[2.]])
>>> b = 1
>>> with tf.GradientTape() as tape:
... CF = 1/2*tf.reduce_sum(tf.square(tf.matmul(x,w)+b-y))
...
>>> b_grad = tape.gradient(CF,b)
Traceback (most recent call last):
File "", line 1, in
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\eager\backp
rop.py", line 986, in gradient
if not t.dtype.is_floating:
AttributeError: 'int' object has no attribute 'dtype'
//又翻车了。。问题出在b是个普通的常量,初始化成变量才能求导
>>> b = tf.Variable(1.)
>>> with tf.GradientTape() as tape:
... CF = 1/2*tf.reduce_sum(tf.square(tf.matmul(x,w)+b-y))
...
>>> b_grad = tape.gradient(CF,b)
>>> print(b_grad)
tf.Tensor(15.0, shape=(), dtype=float32) //emmm~为什么等于15?偶谢特马惹发克,看不懂呐。。
1. 引入数据
2. 对数据进行处理,特征缩放
3. 初始化参数【w】【b】
4. 设置迭代次数
5. 设置学习率(SGD函数)
6. 设置梯度下降迭代器
7. 使用梯度下降记录器
8. 记录器内部记录:定义模型;Cost Function
9. 利用tape.gradient自动计算损失函数关于模型参数的梯度
10.根据梯度自动更新参数
11. 具体参见 机器学习phase1
//numpy处理数据有一套(而且比tensorflow代码简单,少打俩字),引入进行预处理
>>> import numpy as np
>>> x_row = np.array([2013,2014,2015,2016,2017],dtype=np.float32)
>>> y_row = np.array([12000,14000,15000,16500,17500],dtype=np.float32)
>>>
>>> X = (x_row - x_row.min())/(x_row.max()-x_row.min())
>>> Y = (y_row - y_row.min())/(y_row.max()-y_row.min()) //此处的处理第一眼看有点懵
>>> x_row - x_row.min()
array([0., 1., 2., 3., 4.], dtype=float32)
>>> X
array([0. , 0.25, 0.5 , 0.75, 1. ], dtype=float32)
>>> Y
array([0. , 0.36363637, 0.54545456, 0.8181818 , 1. ],
dtype=float32)
//到这儿就看懂了,这就是特征缩放呐,这样做有利于梯度下降
//分析上述操作,x_row - x_row.min()所作的是将x_row向量每一项都减去该向量中的最小值,即
x_row.min(),这一步操作产生的结果就是 新的向量x_row都缩小了,并且必定有一项是0(即原来那个
x_row.min()项)。再看分母是 x_row.max()-x_row.min() >= 0 , 在上下相除之后,必定有一项是0,
还有一项是1(即原来那个x_row.max(),该项的分子分母相等),其余的项都是在0~1之间,所以说,这
一顿骚操作,成功的把向量x_row 中每一项的值都限定在了0~1之间,这样梯度下的就快多了
//上tensorflow
>>> import tensorflow as tf
>>> x = tf.constant(X) //引入数据
>>> y = tf.constant(Y)
>>> w = tf.Variable(0.) //初始化参数为0.就行了(注意dtype一定得是float32呐,不然报错又得敲一遍。。)
>>> b = tf.Variable(0.)
>>> variables = [w,b] //变量组
>>> num_epoch = 10000 //梯度下降的次数就设为10000了
>>> optimizer = tf.keras.optimizers.SGD(learning_rate=1e-3) //声明一个Gradient Descent Optimizer(梯度下降优化器)
>>> optimizer = tf.keras.optimizers.SGD(1e-3) //能省点代码就省一点啊
//在optimizer(优化器)中设定学习率为1e-3,是个负数,大概是-0.28,可以实现缓缓的下降,讲究~
>>> for e in range(num_epoch):
... with tf.GradientTape() as tape:
... y_pred = w*x+b
... CF = 0.5 * tf.reduce_sum(tf.square(y_pred - y))
... grads = tape.gradient(CF,variables)
... optimizer.apply_gradients(grads_and_vars=zip(grads,variables))
...
WARNING: Logging before flag parsing goes to stderr.
W0815 22:40:00.175946 18276 backprop.py:990] The dtype of the source tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32
W0815 22:40:00.180869 18276 backprop.py:990] The dtype of the source tensor must be floating (e.g. tf.float32) when calling GradientTape.gradient, got tf.int32
Traceback (most recent call last):
File "", line 6, in
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\keras\optimizer_v2\optimizer_v2.py", line 427, in apply_gradients
grads_and_vars = _filter_grads(grads_and_vars)
File "C:\Users\12521\Anaconda3\envs\tf\lib\site-packages\tensorflow\python\keras\optimizer_v2\optimizer_v2.py", line 975, in _filter_grads
([v.name for _, v in grads_and_vars],))
ValueError: No gradients provided for any variable: ['Variable:0', 'Variable:0'].
//欧谢他妈惹法克,又翻车。。
>>> for e in range(num_epoch): //设置for循环
... with tf.GradientTape() as tape: //梯度下降记录器
... y_pred = w*x+b //模型
... CF = 0.5 * tf.reduce_sum(tf.square(y_pred - y)) //Cost Function
... grads = tape.gradient(CF,variables) //求偏导
... optimizer.apply_gradients(grads_and_vars=zip(grads,variables))
...
//此处省略9998行梯度下降记录~
//代码的进一步说明:
//调用优化器的apply_gradients()方法,传入Cost function 和 参数,优化器能帮我们在进行完一次梯度
下降之后按照我们之前设定的 learning_rate(在这里我们设定的值是1e-3)自动更新参数.
//函数需要提供的参数 grads_and_vars 包括两部分,一是要求的偏导数(此处即grads,Cost Function对
变量的偏导数);另一个就是要更新的变量(此处即variables)。
//两者需要一个 zip()函数打包一下,具体效果试试看
//效果代码:
>>> grads
[,
]
>>> grads.numpy()
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'list' object has no attribute 'numpy' //是个列表?
>>> type(grads)
>>> type(variables)
//都是个列表
>>> yo = zip(grads,variables)
>>> type(yo)
//打包之后的类型是 zip object
>>> print(yo)
>>> list(yo) //用列表的形式能够展示出来
[(, ), (, )]
//梯度下降最后结果:
>>> print(w,b)
>>> print(w.numpy(),b.numpy()) //结果用numpy格式展示,梯度下降成功!
0.97637 0.057565063
//
欲戴桂冠,必承其重. --酒后听得真言
心满意足的一天。19.8.16