# coding: utf-8
"""张量的基本运算"""
# In[9]:
A = tf.constant([[1., 2.], [3., 4.]])
B = tf.constant([[5., 6.], [7., 8.]])
# output:
(<tf.Tensor: id=31, shape=(2, 2), dtype=float32, numpy=
array([[1., 2.],
[3., 4.]], dtype=float32)>,
<tf.Tensor: id=32, shape=(2, 2), dtype=float32, numpy=
array([[5., 6.],
[7., 8.]], dtype=float32)>)
# In[11]:
C = tf.add(A, B)
# output:
<tf.Tensor: id=33, shape=(2, 2), dtype=float32, numpy=
array([[ 6., 8.],
[10., 12.]], dtype=float32)>
# In[13]:
D = tf.matmul(A,B)
# output:
<tf.Tensor: id=34, shape=(2, 2), dtype=float32, numpy=
array([[19., 22.],
[43., 50.]], dtype=float32)>
""" 自动求导机制 """
# In[8]:
import tensorflow as tf
x = tf.Variable(initial_value=3.) #用变量的好处是默认打开梯度追踪
with tf.GradientTape() as tape: # 在 tf.GradientTape() 的上下文内,所有计算步骤都会被记录以用于求导。————记录器
y = tf.square(x)
y_grad = tape.gradient(y, x) # 计算y关于x的导数——求导方法
print([y, y_grad])
# output:
[<tf.Tensor: id=26, shape=(), dtype=float32, numpy=9.0>, <tf.Tensor: id=30, shape=(), dtype=float32, numpy=6.0>]
# In[6]:
import tensorflow as tf
X = tf.constant([[1.,2.],[3.,4.]])
y = tf.constant([[1.],[2.]])
w = tf.Variable(initial_value = [[1.],[2.]]) #变量的初始化器:initial_value
b = tf.Variable(initial_value = 1.)
with tf.GradientTape() as tape:
L = tf.reduce_sum(tf.square(tf.matmul(X,w) + b - y))
#tf.reduce_sum可以通过设置axis来对不同维度求和;tf.reduce_sum(X,0) = = [4,6] ;tf.reduce_sum(X,1) = = [3,7];tf.reduce_sum(X) = = 10
#tf.square对tensor里的每一个元素平方,但是不改变tensor的shape
w_grad,b_grad = tape.gradient(L,[w,b])
print([L.numpy(),w_grad.numpy(),b_grad.numpy()])#tensor.numpy()取tensor的值,忽略类型信息
print([L,w_grad,b_grad])
"""线性回归示例"""
X,y
# ### 梯度下降法
# #### 首先构建损失函数
# #### 其次求参数梯度,更新参数
# #### 迭代下一轮
# L = sum_{i=1}^n(ax_i + b - y_i)^2
# In[45]:
import numpy as np
X_raw = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32)
y_raw = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32)
X = (X_raw - X_raw.min()) / (X_raw.max() - X_raw.min()) #归一化
y = (y_raw - y_raw.min()) / (y_raw.max() - y_raw.min())
""" 一、NumPy 下的线性回归 """
# In[14]:
a,b = 0, 0
num_epoch = 10000
lr = 1e-3
for e in range(num_epoch):
y_pred = a*X + b
grad_a,grad_b = (y_pred - y).dot(X),(y_pred - y).sum()
a,b = a - lr*grad_a, b-lr*grad_b
print(a,b)
# output:
0.9763702027872221 0.057564988311377796
# #### 再深再复杂的模型就很痛苦了
""" 二、TensorFlow 下的线性回归"""
# ### 默认开启Eager Execution(动态图)模式
# In[47]:
X= tf.constant(X) #tensor化
y = tf.constant(y)
a = tf.Variable(initial_value = 0.) #参数初始化
b = tf.Variable(initial_value = 0.)
variables = [a,b]
num_epoch = 10000
optimizer = tf.keras.optimizers.SGD(learning_rate = 1e-3) #声明优化器
for e in range(num_epoch):
with tf.GradientTape() as tape: #对正向传播和损失函数,开启梯度记录器
y_pred = a*X+b
loss = 0.5*tf.reduce_sum(tf.square(y_pred - y))
grads = tape.gradient(loss,variables) #计算梯度
optimizer.apply_gradients(grads_and_vars = zip(grads,varibales))
#更新参数关键字:grads_and_vars: 需要传入一个python列表,[(grad_a, a), (grad_b, b)] 。
#因此用python内置函数zip(g,v) 将参数和梯度打包拼装成需要的参数形式
#梯度归0
print(a,b)
# output:
<tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0> <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0>
""" python内置函数zip"""
# In[42]:
a = [1, 3, 5]
b = [2, 4, 6]
zip(a,b)
# output:
[(1,2),(3,4),(5,6) ]
"""
整个流程总结:
"""
构建模型 tf.keras.Model 和tf.keras.layers
模型损失:tf.keras.losses
模型优化器:tf.keras.optimizer
模型评估:tf.keras.metrics
"""
import tensorflow as tf
import numpy as np
class MyModel(tf.keras.Model):
def __init__(self):
super().__init__() # Python 2 下使用 super(MyModel, self).__init__()
# 此处添加初始化代码(包含 call 方法中会用到的层),例如
# layer1 = tf.keras.layers.BuiltInLayer(...)
# layer2 = MyCustomLayer(...)
def call(self, input): #实现的是模型的调用 y_pred = Model(X)的过程
#此处添加模型调用的代码(处理输入并返回输出),例如
x = layer1(input)
output = layer2(x)
return output
# 还可以添加自定义的方法
"""
layers对变量和计算流程进行封装(如全连接层dense,卷积层,池化层),Model对各种layers进行组织链接,并封装成一个整体,Model描述的是由输入到输出的运算过程。
模型定义通过继承父类tf.keras.Model实现,还要重写init() (构造函数,初始化)和 call(input) (模型调用,重写)两个方法,同时也可以根据需要增加自定义的方法。
构造函数初始化模型所需的所有层,call()方法描述了输入如何由输入数据得通过layers得到输出
"""
"""
kernel_initializer 、 bias_initializer :权重矩阵 kernel 和偏置向量 bias 两个变量的初始化器。默认为 tf.glorot_uniform_initializer 1 。设置为 tf.zeros_initializer 表示将两个变量均初始化为全 0
"""
模型继承:
class Linear(tf.keras.Model):
模型实例化
model = Linear() #相当于Linear.call()
"""
模型为何非要继承并重写父类tf.keras.Model实现?? 因为父类实现了很多包括其他的属性,如在实例化模型后,可以用model.variable直接获得模型所有变量等,因此要继承。
#相当于Linear.call() 私有属性 父类tf.keras.Model其实定义了call()方法来,为何不直接重写call()来调用Linear() y_pred = Linear(X).而是又实现一个call()方法暴露出来来重写呢? 这是因为后期 Keras 在模型调用的前后还需要有一些自己的内部操作,所以暴露出一个专门用于重载的 call() 方法,然后我们去重写
"""