1 # coding: utf-8 2 3 """张量的基本运算""" 4 5 # In[9]: 6 7 A = tf.constant([[1., 2.], [3., 4.]]) 8 B = tf.constant([[5., 6.], [7., 8.]]) 9 10 # output: 11 12 (<tf.Tensor: id=31, shape=(2, 2), dtype=float32, numpy= 13 array([[1., 2.], 14 [3., 4.]], dtype=float32)>, 15 <tf.Tensor: id=32, shape=(2, 2), dtype=float32, numpy= 16 array([[5., 6.], 17 [7., 8.]], dtype=float32)>) 18 19 20 # In[11]: 21 22 C = tf.add(A, B) 23 24 # output: 25 26 <tf.Tensor: id=33, shape=(2, 2), dtype=float32, numpy= 27 array([[ 6., 8.], 28 [10., 12.]], dtype=float32)> 29 30 # In[13]: 31 32 D = tf.matmul(A,B) 33 34 # output: 35 36 <tf.Tensor: id=34, shape=(2, 2), dtype=float32, numpy= 37 array([[19., 22.], 38 [43., 50.]], dtype=float32)> 39 40 41 """ 自动求导机制 """ 42 43 # In[8]: 44 45 import tensorflow as tf 46 47 x = tf.Variable(initial_value=3.) #用变量的好处是默认打开梯度追踪 48 with tf.GradientTape() as tape: # 在 tf.GradientTape() 的上下文内,所有计算步骤都会被记录以用于求导。————记录器 49 y = tf.square(x) 50 y_grad = tape.gradient(y, x) # 计算y关于x的导数——求导方法 51 print([y, y_grad]) 52 53 # output: 54 [<tf.Tensor: id=26, shape=(), dtype=float32, numpy=9.0>, <tf.Tensor: id=30, shape=(), dtype=float32, numpy=6.0>] 55 56 57 # In[6]: 58 59 import tensorflow as tf 60 X = tf.constant([[1.,2.],[3.,4.]]) 61 y = tf.constant([[1.],[2.]]) 62 w = tf.Variable(initial_value = [[1.],[2.]]) #变量的初始化器:initial_value 63 b = tf.Variable(initial_value = 1.) 64 with tf.GradientTape() as tape: 65 L = tf.reduce_sum(tf.square(tf.matmul(X,w) + b - y)) 66 #tf.reduce_sum可以通过设置axis来对不同维度求和;tf.reduce_sum(X,0) = = [4,6] ;tf.reduce_sum(X,1) = = [3,7];tf.reduce_sum(X) = = 10 67 #tf.square对tensor里的每一个元素平方,但是不改变tensor的shape 68 w_grad,b_grad = tape.gradient(L,[w,b]) 69 print([L.numpy(),w_grad.numpy(),b_grad.numpy()])#tensor.numpy()取tensor的值,忽略类型信息 70 print([L,w_grad,b_grad]) 71 72 73 """线性回归示例""" 74 75 X,y 76 77 # ### 梯度下降法 78 # #### 首先构建损失函数 79 # #### 其次求参数梯度,更新参数 80 # #### 迭代下一轮 81 82 # L = sum_{i=1}^n(ax_i + b - y_i)^2 83 84 85 # In[45]: 86 87 import numpy as np 88 89 X_raw = np.array([2013, 2014, 2015, 2016, 2017], dtype=np.float32) 90 y_raw = np.array([12000, 14000, 15000, 16500, 17500], dtype=np.float32) 91 92 X = (X_raw - X_raw.min()) / (X_raw.max() - X_raw.min()) #归一化 93 y = (y_raw - y_raw.min()) / (y_raw.max() - y_raw.min()) 94 95 96 97 98 """ 一、NumPy 下的线性回归 """ 99 100 # In[14]: 101 102 a,b = 0, 0 103 num_epoch = 10000 104 lr = 1e-3 105 for e in range(num_epoch): 106 y_pred = a*X + b 107 grad_a,grad_b = (y_pred - y).dot(X),(y_pred - y).sum() 108 a,b = a - lr*grad_a, b-lr*grad_b 109 print(a,b) 110 111 # output: 112 0.9763702027872221 0.057564988311377796 113 114 # #### 再深再复杂的模型就很痛苦了 115 116 """ 二、TensorFlow 下的线性回归""" 117 118 # ### 默认开启Eager Execution(动态图)模式 119 120 # In[47]: 121 122 X= tf.constant(X) #tensor化 123 y = tf.constant(y) 124 125 a = tf.Variable(initial_value = 0.) #参数初始化 126 b = tf.Variable(initial_value = 0.) 127 128 variables = [a,b] 129 130 num_epoch = 10000 131 optimizer = tf.keras.optimizers.SGD(learning_rate = 1e-3) #声明优化器 132 for e in range(num_epoch): 133 with tf.GradientTape() as tape: #对正向传播和损失函数,开启梯度记录器 134 y_pred = a*X+b 135 loss = 0.5*tf.reduce_sum(tf.square(y_pred - y)) 136 grads = tape.gradient(loss,variables) #计算梯度 137 optimizer.apply_gradients(grads_and_vars = zip(grads,varibales)) 138 #更新参数关键字:grads_and_vars: 需要传入一个python列表,[(grad_a, a), (grad_b, b)] 。 139 #因此用python内置函数zip(g,v) 将参数和梯度打包拼装成需要的参数形式 140 #梯度归0 141 print(a,b) 142 143 # output: 144 <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0> <tf.Variable 'Variable:0' shape=() dtype=float32, numpy=0.0> 145 146 147 148 """ python内置函数zip""" 149 150 # In[42]: 151 a = [1, 3, 5] 152 b = [2, 4, 6] 153 zip(a,b) 154 155 # output: 156 [(1,2),(3,4),(5,6) ] 157 158 """ 159 整个流程总结: 160 """ 161 构建模型 tf.keras.Model 和tf.keras.layers 162 模型损失:tf.keras.losses 163 模型优化器:tf.keras.optimizer 164 模型评估:tf.keras.metrics 165 """ 166 167 import tensorflow as tf 168 import numpy as np 169 class MyModel(tf.keras.Model): 170 def __init__(self): 171 super().__init__() # Python 2 下使用 super(MyModel, self).__init__() 172 # 此处添加初始化代码(包含 call 方法中会用到的层),例如 173 # layer1 = tf.keras.layers.BuiltInLayer(...) 174 # layer2 = MyCustomLayer(...) 175 176 def call(self, input): #实现的是模型的调用 y_pred = Model(X)的过程 177 #此处添加模型调用的代码(处理输入并返回输出),例如 178 x = layer1(input) 179 output = layer2(x) 180 return output 181 182 # 还可以添加自定义的方法 183 """ 184 layers对变量和计算流程进行封装(如全连接层dense,卷积层,池化层),Model对各种layers进行组织链接,并封装成一个整体,Model描述的是由输入到输出的运算过程。 185 模型定义通过继承父类tf.keras.Model实现,还要重写init() (构造函数,初始化)和 call(input) (模型调用,重写)两个方法,同时也可以根据需要增加自定义的方法。 186 构造函数初始化模型所需的所有层,call()方法描述了输入如何由输入数据得通过layers得到输出 187 """ 188 189 """ 190 kernel_initializer 、 bias_initializer :权重矩阵 kernel 和偏置向量 bias 两个变量的初始化器。默认为 tf.glorot_uniform_initializer 1 。设置为 tf.zeros_initializer 表示将两个变量均初始化为全 0 191 """ 192 193 194 195 #模型继承: 196 class Linear(tf.keras.Model): 197 198 #模型实例化 199 model = Linear() #相当于Linear.call() 200 201 """ 202 模型为何非要继承并重写父类tf.keras.Model实现?? 因为父类实现了很多包括其他的属性,如在实例化模型后,可以用model.variable直接获得模型所有变量等,因此要继承。 203 204 #相当于Linear.call() 私有属性 父类tf.keras.Model其实定义了call()方法来,为何不直接重写call()来调用Linear() y_pred = Linear(X).而是又实现一个call()方法暴露出来来重写呢? 这是因为后期 Keras 在模型调用的前后还需要有一些自己的内部操作,所以暴露出一个专门用于重载的 call() 方法,然后我们去重写 205 """