diff --git "a/3-1,\344\275\216\351\230\266API\347\244\272\350\214\203.md" "b/3-1,\344\275\216\351\230\266API\347\244\272\350\214\203.md" index cc25a471..e1dca81a 100644 --- "a/3-1,\344\275\216\351\230\266API\347\244\272\350\214\203.md" +++ "b/3-1,\344\275\216\351\230\266API\347\244\272\350\214\203.md" @@ -1,6 +1,6 @@ # 3-1,低阶API示范 -下面的范例使用TensorFlow的低阶API实现线性回归模型。 +下面的范例使用TensorFlow的低阶API实现线性回归模型和DNN二分类模型。 低阶API主要包括张量操作,计算图和自动微分。 @@ -10,8 +10,7 @@ import tensorflow as tf #打印时间分割线 @tf.function def printbar(): - ts = tf.timestamp() - today_ts = ts%(24*60*60) + today_ts = tf.timestamp()%(24*60*60) hour = tf.cast(today_ts//3600+8,tf.int32)%tf.constant(24) minite = tf.cast((today_ts%3600)//60,tf.int32) @@ -25,83 +24,534 @@ def printbar(): timestring = tf.strings.join([timeformat(hour),timeformat(minite), timeformat(second)],separator = ":") - tf.print("=========="*8,end = "") - tf.print(timestring) + tf.print("=========="*8+timestring) + ``` ```python + +``` + +### 一,线性回归模型 + + +**1,准备数据** + +```python +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import tensorflow as tf + + #样本数量 n = 400 # 生成测试用数据集 X = tf.random.uniform([n,2],minval=-10,maxval=10) -w0 = tf.constant([[2.0],[-1.0]]) -b0 = tf.constant(3.0) +w0 = tf.constant([[2.0],[-3.0]]) +b0 = tf.constant([[3.0]]) Y = X@w0 + b0 + tf.random.normal([n,1],mean = 0.0,stddev= 2.0) # @表示矩阵乘法,增加正态扰动 ``` ```python -#使用动态图调试 +# 数据可视化 +%matplotlib inline +%config InlineBackend.figure_format = 'svg' + +plt.figure(figsize = (12,5)) +ax1 = plt.subplot(121) +ax1.scatter(X[:,0],Y[:,0], c = "b") +plt.xlabel("x1") +plt.ylabel("y",rotation = 0) + +ax2 = plt.subplot(122) +ax2.scatter(X[:,1],Y[:,0], c = "g") +plt.xlabel("x2") +plt.ylabel("y",rotation = 0) +plt.show() + +``` + +![](./data/3-1-01-回归数据可视化.png) + +```python +# 构建数据管道迭代器 +def data_iter(features, labels, batch_size=8): + num_examples = len(features) + indices = list(range(num_examples)) + np.random.shuffle(indices) #样本的读取顺序是随机的 + for i in range(0, num_examples, batch_size): + indexs = indices[i: min(i + batch_size, num_examples)] + yield tf.gather(X,indexs), tf.gather(Y,indexs) + +# 测试数据管道效果 +batch_size = 8 +(features,labels) = next(data_iter(X,Y,batch_size)) +print(features) +print(labels) + +``` + +``` +tf.Tensor( +[[ 2.6161194 0.11071014] + [ 9.79207 -0.70180416] + [ 9.792343 6.9149055 ] + [-2.4186516 -9.375019 ] + [ 9.83749 -3.4637213 ] + [ 7.3953056 4.374569 ] + [-0.14686584 -0.28063297] + [ 0.49001217 -9.739792 ]], shape=(8, 2), dtype=float32) +tf.Tensor( +[[ 9.334667 ] + [22.058844 ] + [ 3.0695205] + [26.736238 ] + [35.292133 ] + [ 4.2943544] + [ 1.6713585] + [34.826904 ]], shape=(8, 1), dtype=float32) +``` + + +**2,定义模型** + +```python w = tf.Variable(tf.random.normal(w0.shape)) -b = tf.Variable(0.0) - -def train(epoches): - for epoch in tf.range(1,epoches+1): - with tf.GradientTape() as tape: - #正向传播求损失 - Y_hat = X@w + b - loss = tf.squeeze(tf.transpose(Y-Y_hat)@(Y-Y_hat))/(2.0*n) - - # 反向传播求梯度 - dloss_dw,dloss_db = tape.gradient(loss,[w,b]) - # 梯度下降法更新参数 - w.assign(w - 0.001*dloss_dw) - b.assign(b - 0.001*dloss_db) - if epoch%1000 == 0: +b = tf.Variable(tf.zeros_like(b0,dtype = tf.float32)) + +# 定义模型 +class LinearRegression: + #正向传播 + def __call__(self,x): + return x@w + b + + # 损失函数 + def loss_func(self,y_true,y_pred): + return tf.reduce_mean((y_true - y_pred)**2/2) + +model = LinearRegression() +``` + +```python + +``` + +**3,训练模型** + +```python +# 使用动态图调试 +def train_step(model, features, labels): + with tf.GradientTape() as tape: + predictions = model(features) + loss = model.loss_func(labels, predictions) + # 反向传播求梯度 + dloss_dw,dloss_db = tape.gradient(loss,[w,b]) + # 梯度下降法更新参数 + w.assign(w - 0.001*dloss_dw) + b.assign(b - 0.001*dloss_db) + + return loss + +``` + +```python +# 测试train_step效果 +batch_size = 10 +(features,labels) = next(data_iter(X,Y,batch_size)) +train_step(model,features,labels) + +``` + +``` + +``` + +```python +def train_model(model,epochs): + for epoch in tf.range(1,epochs+1): + for features, labels in data_iter(X,Y,10): + loss = train_step(model,features,labels) + + if epoch%50==0: printbar() - tf.print("epoch =",epoch," loss =",loss,) + tf.print("epoch =",epoch,"loss = ",loss) tf.print("w =",w) tf.print("b =",b) - tf.print("") - -train(5000) + +train_model(model,epochs = 200) + +``` + ``` +================================================================================16:35:56 +epoch = 50 loss = 1.78806472 +w = [[1.97554708] + [-2.97719598]] +b = [[2.60692883]] +================================================================================16:36:00 +epoch = 100 loss = 2.64588404 +w = [[1.97319281] + [-2.97810626]] +b = [[2.95525956]] +================================================================================16:36:04 +epoch = 150 loss = 1.42576694 +w = [[1.96466208] + [-2.98337793]] +b = [[3.00264144]] +================================================================================16:36:08 +epoch = 200 loss = 1.68992615 +w = [[1.97718477] + [-2.983814]] +b = [[3.01013041]] +``` + +```python -![](./data/3-1-输出01.jpg) +``` ```python ##使用autograph机制转换成静态图加速 -w = tf.Variable(tf.random.normal(w0.shape)) -b = tf.Variable(0.0) - @tf.function -def train(epoches): - for epoch in tf.range(1,epoches+1): - with tf.GradientTape() as tape: - #正向传播求损失 - Y_hat = X@w + b - loss = tf.squeeze(tf.transpose(Y-Y_hat)@(Y-Y_hat))/(2.0*n) - - # 反向传播求梯度 - dloss_dw,dloss_db = tape.gradient(loss,[w,b]) - # 梯度下降法更新参数 - w.assign(w - 0.001*dloss_dw) - b.assign(b - 0.001*dloss_db) - if epoch%1000 == 0: +def train_step(model, features, labels): + with tf.GradientTape() as tape: + predictions = model(features) + loss = model.loss_func(labels, predictions) + # 反向传播求梯度 + dloss_dw,dloss_db = tape.gradient(loss,[w,b]) + # 梯度下降法更新参数 + w.assign(w - 0.001*dloss_dw) + b.assign(b - 0.001*dloss_db) + + return loss + +def train_model(model,epochs): + for epoch in tf.range(1,epochs+1): + for features, labels in data_iter(X,Y,10): + loss = train_step(model,features,labels) + if epoch%50==0: printbar() - tf.print("epoch =",epoch," loss =",loss,) + tf.print("epoch =",epoch,"loss = ",loss) tf.print("w =",w) tf.print("b =",b) - tf.print("") -train(5000) + +train_model(model,epochs = 200) + ``` -![](./data/3-1-输出02.jpg) +``` +================================================================================16:36:35 +epoch = 50 loss = 0.894210339 +w = [[1.96927285] + [-2.98914337]] +b = [[3.00987792]] +================================================================================16:36:36 +epoch = 100 loss = 1.58621466 +w = [[1.97566223] + [-2.98550248]] +b = [[3.00998402]] +================================================================================16:36:37 +epoch = 150 loss = 2.2695992 +w = [[1.96664226] + [-2.99248481]] +b = [[3.01028705]] +================================================================================16:36:38 +epoch = 200 loss = 1.90848124 +w = [[1.98000824] + [-2.98888135]] +b = [[3.01085401]] +``` + +```python + +``` + +```python +# 结果可视化 + +%matplotlib inline +%config InlineBackend.figure_format = 'svg' + +plt.figure(figsize = (12,5)) +ax1 = plt.subplot(121) +ax1.scatter(X[:,0],Y[:,0], c = "b",label = "samples") +ax1.plot(X[:,0],w[0]*X[:,0]+b[0],"-r",linewidth = 5.0,label = "model") +ax1.legend() +plt.xlabel("x1") +plt.ylabel("y",rotation = 0) + + +ax2 = plt.subplot(122) +ax2.scatter(X[:,1],Y[:,0], c = "g",label = "samples") +ax2.plot(X[:,1],w[1]*X[:,1]+b[0],"-r",linewidth = 5.0,label = "model") +ax2.legend() +plt.xlabel("x2") +plt.ylabel("y",rotation = 0) + +plt.show() +``` + +![](./data/3-1-2-回归结果可视化.png) + +```python + +``` + +### 二,DNN二分类模型 + +```python +``` + +**1,准备数据** + +```python +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import tensorflow as tf +%matplotlib inline +%config InlineBackend.figure_format = 'svg' + +#正负样本数量 +n_positive,n_negative = 2000,2000 + +#生成正样本, 小圆环分布 +r_p = 5.0 + tf.random.truncated_normal([n_positive,1],0.0,1.0) +theta_p = tf.random.uniform([n_positive,1],0.0,2*np.pi) +Xp = tf.concat([r_p*tf.cos(theta_p),r_p*tf.sin(theta_p)],axis = 1) +Yp = tf.ones_like(r_p) + +#生成负样本, 大圆环分布 +r_n = 8.0 + tf.random.truncated_normal([n_negative,1],0.0,1.0) +theta_n = tf.random.uniform([n_negative,1],0.0,2*np.pi) +Xn = tf.concat([r_n*tf.cos(theta_n),r_n*tf.sin(theta_n)],axis = 1) +Yn = tf.zeros_like(r_n) + +#汇总样本 +X = tf.concat([Xp,Xn],axis = 0) +Y = tf.concat([Yp,Yn],axis = 0) + + +#可视化 +plt.figure(figsize = (6,6)) +plt.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r") +plt.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g") +plt.legend(["positive","negative"]); + +``` + +![](./data/3-1-03-分类数据可视化.png) + +```python +# 构建数据管道迭代器 +def data_iter(features, labels, batch_size=8): + num_examples = len(features) + indices = list(range(num_examples)) + np.random.shuffle(indices) #样本的读取顺序是随机的 + for i in range(0, num_examples, batch_size): + indexs = indices[i: min(i + batch_size, num_examples)] + yield tf.gather(X,indexs), tf.gather(Y,indexs) + +# 测试数据管道效果 +batch_size = 10 +(features,labels) = next(data_iter(X,Y,batch_size)) +print(features) +print(labels) +``` + +``` +tf.Tensor( +[[ 0.03732629 3.5783494 ] + [ 0.542919 5.035079 ] + [ 5.860281 -2.4476354 ] + [ 0.63657564 3.194231 ] + [-3.5072308 2.5578873 ] + [-2.4109735 -3.6621518 ] + [ 4.0975413 -2.4172943 ] + [ 1.9393908 -6.782317 ] + [-4.7453732 -0.5176727 ] + [-1.4057113 -7.9775257 ]], shape=(10, 2), dtype=float32) +tf.Tensor( +[[1.] + [1.] + [0.] + [1.] + [1.] + [1.] + [1.] + [0.] + [1.] + [0.]], shape=(10, 1), dtype=float32) +``` + +```python + +``` + +**2,定义模型** + + +此处范例我们利用tf.Module来组织模型变量,关于tf.Module的较详细介绍参考本书第四章最后一节: Autograph和tf.Module。 + +```python +class DNNModel(tf.Module): + def __init__(self,name = None): + super(DNNModel, self).__init__(name=name) + self.w1 = tf.Variable(tf.random.truncated_normal([2,4]),dtype = tf.float32) + self.b1 = tf.Variable(tf.zeros([1,4]),dtype = tf.float32) + self.w2 = tf.Variable(tf.random.truncated_normal([4,8]),dtype = tf.float32) + self.b2 = tf.Variable(tf.zeros([1,8]),dtype = tf.float32) + self.w3 = tf.Variable(tf.random.truncated_normal([8,1]),dtype = tf.float32) + self.b3 = tf.Variable(tf.zeros([1,1]),dtype = tf.float32) + + + # 正向传播 + @tf.function(input_signature=[tf.TensorSpec(shape = [None,2], dtype = tf.float32)]) + def __call__(self,x): + x = tf.nn.relu(x@self.w1 + self.b1) + x = tf.nn.relu(x@self.w2 + self.b2) + y = tf.nn.sigmoid(x@self.w3 + self.b3) + return y + + # 损失函数(二元交叉熵) + @tf.function(input_signature=[tf.TensorSpec(shape = [None,1], dtype = tf.float32), + tf.TensorSpec(shape = [None,1], dtype = tf.float32)]) + def loss_func(self,y_true,y_pred): + #将预测值限制在1e-7以上, 1-e-7以下,避免log(0)错误 + eps = 1e-7 + y_pred = tf.clip_by_value(y_pred,eps,1.0-eps) + bce = - y_true*tf.math.log(y_pred) - (1-y_true)*tf.math.log(1-y_pred) + return tf.reduce_mean(bce) + + # 评估指标(准确率) + @tf.function(input_signature=[tf.TensorSpec(shape = [None,1], dtype = tf.float32), + tf.TensorSpec(shape = [None,1], dtype = tf.float32)]) + def metric_func(self,y_true,y_pred): + y_pred = tf.where(y_pred>0.5,tf.ones_like(y_pred,dtype = tf.float32), + tf.zeros_like(y_pred,dtype = tf.float32)) + acc = tf.reduce_mean(1-tf.abs(y_true-y_pred)) + return acc + +model = DNNModel() +``` + +```python +# 测试模型结构 +batch_size = 10 +(features,labels) = next(data_iter(X,Y,batch_size)) + +predictions = model(features) + +loss = model.loss_func(labels,predictions) +metric = model.metric_func(labels,predictions) + +tf.print("init loss:",loss) +tf.print("init metric",metric) +``` + +``` +init loss: 1.76568353 +init metric 0.6 +``` + +```python +print(len(model.trainable_variables)) +``` + +``` +6 +``` + +```python + +``` + +**3,训练模型** + +```python +##使用autograph机制转换成静态图加速 + +@tf.function +def train_step(model, features, labels): + + # 正向传播求损失 + with tf.GradientTape() as tape: + predictions = model(features) + loss = model.loss_func(labels, predictions) + + # 反向传播求梯度 + grads = tape.gradient(loss, model.trainable_variables) + + # 执行梯度下降 + for p, dloss_dp in zip(model.trainable_variables,grads): + p.assign(p - 0.001*dloss_dp) + + # 计算评估指标 + metric = model.metric_func(labels,predictions) + + return loss, metric + + +def train_model(model,epochs): + for epoch in tf.range(1,epochs+1): + for features, labels in data_iter(X,Y,100): + loss,metric = train_step(model,features,labels) + if epoch%100==0: + printbar() + tf.print("epoch =",epoch,"loss = ",loss, "accuracy = ", metric) + + +train_model(model,epochs = 600) +``` + +``` +================================================================================16:47:35 +epoch = 100 loss = 0.567795336 accuracy = 0.71 +================================================================================16:47:39 +epoch = 200 loss = 0.50955683 accuracy = 0.77 +================================================================================16:47:43 +epoch = 300 loss = 0.421476126 accuracy = 0.84 +================================================================================16:47:47 +epoch = 400 loss = 0.330618203 accuracy = 0.9 +================================================================================16:47:51 +epoch = 500 loss = 0.308296859 accuracy = 0.89 +================================================================================16:47:55 +epoch = 600 loss = 0.279367268 accuracy = 0.96 +``` + +```python + +``` + +```python +# 结果可视化 +fig, (ax1,ax2) = plt.subplots(nrows=1,ncols=2,figsize = (12,5)) +ax1.scatter(Xp[:,0],Xp[:,1],c = "r") +ax1.scatter(Xn[:,0],Xn[:,1],c = "g") +ax1.legend(["positive","negative"]); +ax1.set_title("y_true"); + +Xp_pred = tf.boolean_mask(X,tf.squeeze(model(X)>=0.5),axis = 0) +Xn_pred = tf.boolean_mask(X,tf.squeeze(model(X)<0.5),axis = 0) + +ax2.scatter(Xp_pred[:,0],Xp_pred[:,1],c = "r") +ax2.scatter(Xn_pred[:,0],Xn_pred[:,1],c = "g") +ax2.legend(["positive","negative"]); +ax2.set_title("y_pred"); + +``` + +![](./data/3-1-04-分类结果可视化.png) + +```python + +``` 如果对本书内容理解上有需要进一步和作者交流的地方,欢迎在公众号"Python与算法之美"下留言。作者时间和精力有限,会酌情予以回复。 diff --git "a/3-2,\344\270\255\351\230\266API\347\244\272\350\214\203.md" "b/3-2,\344\270\255\351\230\266API\347\244\272\350\214\203.md" index bd514028..221e05d7 100644 --- "a/3-2,\344\270\255\351\230\266API\347\244\272\350\214\203.md" +++ "b/3-2,\344\270\255\351\230\266API\347\244\272\350\214\203.md" @@ -1,19 +1,16 @@ # 3-2,中阶API示范 -下面的范例使用TensorFlow的中阶API实现线性回归模型。 +下面的范例使用TensorFlow的中阶API实现线性回归模型和和DNN二分类模型。 TensorFlow的中阶API主要包括各种模型层,损失函数,优化器,数据管道,特征列等等。 ```python import tensorflow as tf -from tensorflow.keras import layers,losses,metrics,optimizers - #打印时间分割线 @tf.function def printbar(): - ts = tf.timestamp() - today_ts = ts%(24*60*60) + today_ts = tf.timestamp()%(24*60*60) hour = tf.cast(today_ts//3600+8,tf.int32)%tf.constant(24) minite = tf.cast((today_ts%3600)//60,tf.int32) @@ -27,59 +24,384 @@ def printbar(): timestring = tf.strings.join([timeformat(hour),timeformat(minite), timeformat(second)],separator = ":") - tf.print("=========="*8,end = "") - tf.print(timestring) + tf.print("=========="*8+timestring) + ``` ```python + +``` + +### 一,线性回归模型 + + +**1,准备数据** + +```python +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import tensorflow as tf +from tensorflow.keras import layers,losses,metrics,optimizers + #样本数量 -n = 800 +n = 400 # 生成测试用数据集 X = tf.random.uniform([n,2],minval=-10,maxval=10) -w0 = tf.constant([[2.0],[-1.0]]) -b0 = tf.constant(3.0) +w0 = tf.constant([[2.0],[-3.0]]) +b0 = tf.constant([[3.0]]) Y = X@w0 + b0 + tf.random.normal([n,1],mean = 0.0,stddev= 2.0) # @表示矩阵乘法,增加正态扰动 +``` + +```python +# 数据可视化 +%matplotlib inline +%config InlineBackend.figure_format = 'svg' +plt.figure(figsize = (12,5)) +ax1 = plt.subplot(121) +ax1.scatter(X[:,0],Y[:,0], c = "b") +plt.xlabel("x1") +plt.ylabel("y",rotation = 0) + +ax2 = plt.subplot(122) +ax2.scatter(X[:,1],Y[:,0], c = "g") +plt.xlabel("x2") +plt.ylabel("y",rotation = 0) +plt.show() + +``` + +![](./data/3-2-01-回归数据可视化.png) + +```python #构建输入数据管道 ds = tf.data.Dataset.from_tensor_slices((X,Y)) \ - .shuffle(buffer_size = 1000).batch(100) \ + .shuffle(buffer_size = 100).batch(10) \ .prefetch(tf.data.experimental.AUTOTUNE) +``` + +```python + +``` + +**2,定义模型** + +```python +model = layers.Dense(units = 1) +model.build(input_shape = (2,)) #用build方法创建variables +model.loss_func = losses.mean_squared_error +model.optimizer = optimizers.SGD(learning_rate=0.001) +``` -#定义优化器 -optimizer = optimizers.SGD(learning_rate=0.001) +```python ``` +**3,训练模型** + ```python -linear = layers.Dense(units = 1) -linear.build(input_shape = (2,)) +#使用autograph机制转换成静态图加速 @tf.function -def train(epoches): - for epoch in tf.range(1,epoches+1): - L = tf.constant(0.0) #使用L记录loss值 - for X_batch,Y_batch in ds: - with tf.GradientTape() as tape: - Y_hat = linear(X_batch) - loss = losses.mean_squared_error(tf.reshape(Y_hat,[-1]),tf.reshape(Y_batch,[-1])) - grads = tape.gradient(loss,linear.variables) - optimizer.apply_gradients(zip(grads,linear.variables)) - L = loss - - if(epoch%100==0): +def train_step(model, features, labels): + with tf.GradientTape() as tape: + predictions = model(features) + loss = model.loss_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1])) + grads = tape.gradient(loss,model.variables) + model.optimizer.apply_gradients(zip(grads,model.variables)) + return loss + +# 测试train_step效果 +features,labels = next(ds.as_numpy_iterator()) +train_step(model,features,labels) + +``` + +```python +model.variables[0] +model.variables[1] +``` + +```python +@tf.function +def train_model(model,epochs): + for epoch in tf.range(1,epochs+1): + loss = tf.constant(0.0) + for features, labels in ds: + loss = train_step(model,features,labels) + if epoch%50==0: printbar() - tf.print("epoch =",epoch,"loss =",L) - tf.print("w =",linear.kernel) - tf.print("b =",linear.bias) - tf.print("") + tf.print("epoch =",epoch,"loss = ",loss) + tf.print("w =",model.variables[0]) + tf.print("b =",model.variables[1]) +train_model(model,epochs = 200) + +``` + +``` +================================================================================17:01:48 +epoch = 50 loss = 2.56481647 +w = [[1.99355531] + [-2.99061537]] +b = [3.09484935] +================================================================================17:01:51 +epoch = 100 loss = 5.96198225 +w = [[1.98028314] + [-2.96975136]] +b = [3.09501529] +================================================================================17:01:54 +epoch = 150 loss = 4.79625702 +w = [[2.00056171] + [-2.98774862]] +b = [3.09567738] +================================================================================17:01:58 +epoch = 200 loss = 8.26704407 +w = [[2.00282311] + [-2.99300027]] +b = [3.09406662] +``` + +```python + +``` + +```python +# 结果可视化 + +%matplotlib inline +%config InlineBackend.figure_format = 'svg' + +w,b = model.variables + +plt.figure(figsize = (12,5)) +ax1 = plt.subplot(121) +ax1.scatter(X[:,0],Y[:,0], c = "b",label = "samples") +ax1.plot(X[:,0],w[0]*X[:,0]+b[0],"-r",linewidth = 5.0,label = "model") +ax1.legend() +plt.xlabel("x1") +plt.ylabel("y",rotation = 0) + + + +ax2 = plt.subplot(122) +ax2.scatter(X[:,1],Y[:,0], c = "g",label = "samples") +ax2.plot(X[:,1],w[1]*X[:,1]+b[0],"-r",linewidth = 5.0,label = "model") +ax2.legend() +plt.xlabel("x2") +plt.ylabel("y",rotation = 0) + +plt.show() -train(500) ``` -![](./data/3-2-输出01.jpg) +![](./data/3-2-02-回归结果可视化.png) + +```python + +``` + +### 二, DNN二分类模型 + +```python + +``` + +**1,准备数据** + +```python +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import tensorflow as tf +from tensorflow.keras import layers,losses,metrics,optimizers +%matplotlib inline +%config InlineBackend.figure_format = 'svg' + +#正负样本数量 +n_positive,n_negative = 2000,2000 + +#生成正样本, 小圆环分布 +r_p = 5.0 + tf.random.truncated_normal([n_positive,1],0.0,1.0) +theta_p = tf.random.uniform([n_positive,1],0.0,2*np.pi) +Xp = tf.concat([r_p*tf.cos(theta_p),r_p*tf.sin(theta_p)],axis = 1) +Yp = tf.ones_like(r_p) + +#生成负样本, 大圆环分布 +r_n = 8.0 + tf.random.truncated_normal([n_negative,1],0.0,1.0) +theta_n = tf.random.uniform([n_negative,1],0.0,2*np.pi) +Xn = tf.concat([r_n*tf.cos(theta_n),r_n*tf.sin(theta_n)],axis = 1) +Yn = tf.zeros_like(r_n) + +#汇总样本 +X = tf.concat([Xp,Xn],axis = 0) +Y = tf.concat([Yp,Yn],axis = 0) + +#可视化 +plt.figure(figsize = (6,6)) +plt.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r") +plt.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g") +plt.legend(["positive","negative"]); + +``` + +![](./data/3-1-03-分类数据可视化.png) + +```python +#构建输入数据管道 +ds = tf.data.Dataset.from_tensor_slices((X,Y)) \ + .shuffle(buffer_size = 4000).batch(100) \ + .prefetch(tf.data.experimental.AUTOTUNE) +``` + +```python + +``` + +**2, 定义模型** + +```python + +``` + +```python +class DNNModel(tf.Module): + def __init__(self,name = None): + super(DNNModel, self).__init__(name=name) + self.dense1 = layers.Dense(4,activation = "relu") + self.dense2 = layers.Dense(8,activation = "relu") + self.dense3 = layers.Dense(1,activation = "sigmoid") + + + # 正向传播 + @tf.function(input_signature=[tf.TensorSpec(shape = [None,2], dtype = tf.float32)]) + def __call__(self,x): + x = self.dense1(x) + x = self.dense2(x) + y = self.dense3(x) + return y + +model = DNNModel() +model.loss_func = losses.binary_crossentropy +model.metric_func = metrics.binary_accuracy +model.optimizer = optimizers.Adam(learning_rate=0.001) + +``` + +```python +# 测试模型结构 +(features,labels) = next(ds.as_numpy_iterator()) + +predictions = model(features) + +loss = model.loss_func(tf.reshape(labels,[-1]),tf.reshape(predictions,[-1])) +metric = model.metric_func(tf.reshape(labels,[-1]),tf.reshape(predictions,[-1])) + +tf.print("init loss:",loss) +tf.print("init metric",metric) + +``` + +``` +init loss: 1.13653195 +init metric 0.5 +``` + +```python + +``` + +**3,训练模型** + +```python +#使用autograph机制转换成静态图加速 + +@tf.function +def train_step(model, features, labels): + with tf.GradientTape() as tape: + predictions = model(features) + loss = model.loss_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1])) + grads = tape.gradient(loss,model.trainable_variables) + model.optimizer.apply_gradients(zip(grads,model.trainable_variables)) + + metric = model.metric_func(tf.reshape(labels,[-1]), tf.reshape(predictions,[-1])) + + return loss,metric + +# 测试train_step效果 +features,labels = next(ds.as_numpy_iterator()) +train_step(model,features,labels) +``` + +``` +(, + ) +``` + +```python + +``` + +```python +@tf.function +def train_model(model,epochs): + for epoch in tf.range(1,epochs+1): + loss, metric = tf.constant(0.0),tf.constant(0.0) + for features, labels in ds: + loss,metric = train_step(model,features,labels) + if epoch%10==0: + printbar() + tf.print("epoch =",epoch,"loss = ",loss, "accuracy = ",metric) +train_model(model,epochs = 60) + +``` + +``` +================================================================================17:07:36 +epoch = 10 loss = 0.556449413 accuracy = 0.79 +================================================================================17:07:38 +epoch = 20 loss = 0.439187407 accuracy = 0.86 +================================================================================17:07:40 +epoch = 30 loss = 0.259921253 accuracy = 0.95 +================================================================================17:07:42 +epoch = 40 loss = 0.244920313 accuracy = 0.9 +================================================================================17:07:43 +epoch = 50 loss = 0.19839409 accuracy = 0.92 +================================================================================17:07:45 +epoch = 60 loss = 0.126151696 accuracy = 0.95 +``` + +```python + +``` + +```python +# 结果可视化 +fig, (ax1,ax2) = plt.subplots(nrows=1,ncols=2,figsize = (12,5)) +ax1.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r") +ax1.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g") +ax1.legend(["positive","negative"]); +ax1.set_title("y_true"); + +Xp_pred = tf.boolean_mask(X,tf.squeeze(model(X)>=0.5),axis = 0) +Xn_pred = tf.boolean_mask(X,tf.squeeze(model(X)<0.5),axis = 0) + +ax2.scatter(Xp_pred[:,0].numpy(),Xp_pred[:,1].numpy(),c = "r") +ax2.scatter(Xn_pred[:,0].numpy(),Xn_pred[:,1].numpy(),c = "g") +ax2.legend(["positive","negative"]); +ax2.set_title("y_pred"); + + +``` + +![](./data/3-2-04-分类结果可视化.png) + +```python + +``` 如果对本书内容理解上有需要进一步和作者交流的地方,欢迎在公众号"Python与算法之美"下留言。作者时间和精力有限,会酌情予以回复。 diff --git "a/3-3,\351\253\230\351\230\266API\347\244\272\350\214\203.md" "b/3-3,\351\253\230\351\230\266API\347\244\272\350\214\203.md" index 7c662b19..270bcc84 100644 --- "a/3-3,\351\253\230\351\230\266API\347\244\272\350\214\203.md" +++ "b/3-3,\351\253\230\351\230\266API\347\244\272\350\214\203.md" @@ -1,6 +1,6 @@ # 3-3,高阶API示范 -下面的范例使用TensorFlow的高阶API实现线性回归模型。 +下面的范例使用TensorFlow的高阶API实现线性回归模型和DNN二分类模型。 TensorFlow的高阶API主要为tf.keras.models提供的模型的类接口。 @@ -9,139 +9,315 @@ TensorFlow的高阶API主要为tf.keras.models提供的模型的类接口。 此处分别演示使用Sequential按层顺序构建模型以及继承Model基类构建自定义模型。 +```python +import tensorflow as tf -### 一,使用Sequential按层顺序构建模型【面向新手】 +#打印时间分割线 +@tf.function +def printbar(): + today_ts = tf.timestamp()%(24*60*60) + + hour = tf.cast(today_ts//3600+8,tf.int32)%tf.constant(24) + minite = tf.cast((today_ts%3600)//60,tf.int32) + second = tf.cast(tf.floor(today_ts%60),tf.int32) + + def timeformat(m): + if tf.strings.length(tf.strings.format("{}",m))==1: + return(tf.strings.format("0{}",m)) + else: + return(tf.strings.format("{}",m)) + + timestring = tf.strings.join([timeformat(hour),timeformat(minite), + timeformat(second)],separator = ":") + tf.print("=========="*8+timestring) + + +``` + +### 一,线性回归模型 + + +此范例我们使用Sequential按层顺序构建模型,并使用内置model.fit方法训练模型【面向新手】。 + + +**1,准备数据** ```python +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt import tensorflow as tf -from tensorflow.keras import models,layers,optimizers +from tensorflow.keras import models,layers,losses,metrics,optimizers #样本数量 -n = 800 +n = 400 # 生成测试用数据集 X = tf.random.uniform([n,2],minval=-10,maxval=10) -w0 = tf.constant([[2.0],[-1.0]]) -b0 = tf.constant(3.0) - +w0 = tf.constant([[2.0],[-3.0]]) +b0 = tf.constant([[3.0]]) Y = X@w0 + b0 + tf.random.normal([n,1],mean = 0.0,stddev= 2.0) # @表示矩阵乘法,增加正态扰动 + ``` +```python +# 数据可视化 + +%matplotlib inline +%config InlineBackend.figure_format = 'svg' +plt.figure(figsize = (12,5)) +ax1 = plt.subplot(121) +ax1.scatter(X[:,0],Y[:,0], c = "b") +plt.xlabel("x1") +plt.ylabel("y",rotation = 0) + +ax2 = plt.subplot(122) +ax2.scatter(X[:,1],Y[:,0], c = "g") +plt.xlabel("x2") +plt.ylabel("y",rotation = 0) +plt.show() + +``` + +![](./data/3-3-01-回归数据可视化.png) + +```python + +``` + +**2,定义模型** + ```python tf.keras.backend.clear_session() -linear = models.Sequential() -linear.add(layers.Dense(1,input_shape =(2,))) -linear.summary() +model = models.Sequential() +model.add(layers.Dense(1,input_shape =(2,))) +model.summary() +``` + +``` +Model: "sequential" +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +dense (Dense) (None, 1) 3 +================================================================= +Total params: 3 +Trainable params: 3 +Non-trainable params: 0 +``` + +```python + ``` -![](./data/3-3-序列结构.jpg) +**3,训练模型** ```python ### 使用fit方法进行训练 -linear.compile(optimizer="adam",loss="mse",metrics=["mae"]) -linear.fit(X,Y,batch_size = 20,epochs = 200) +model.compile(optimizer="adam",loss="mse",metrics=["mae"]) +model.fit(X,Y,batch_size = 10,epochs = 200) -tf.print("w = ",linear.layers[0].kernel) -tf.print("b = ",linear.layers[0].bias) +tf.print("w = ",model.layers[0].kernel) +tf.print("b = ",model.layers[0].bias) ``` -![](./data/3-3-内置训练.jpg) +``` +Epoch 197/200 +400/400 [==============================] - 0s 190us/sample - loss: 4.3977 - mae: 1.7129 +Epoch 198/200 +400/400 [==============================] - 0s 172us/sample - loss: 4.3918 - mae: 1.7117 +Epoch 199/200 +400/400 [==============================] - 0s 134us/sample - loss: 4.3861 - mae: 1.7106 +Epoch 200/200 +400/400 [==============================] - 0s 166us/sample - loss: 4.3786 - mae: 1.7092 +w = [[1.99339032] + [-3.00866461]] +b = [2.67018795] +``` ```python +# 结果可视化 + +%matplotlib inline +%config InlineBackend.figure_format = 'svg' + +w,b = model.variables +plt.figure(figsize = (12,5)) +ax1 = plt.subplot(121) +ax1.scatter(X[:,0],Y[:,0], c = "b",label = "samples") +ax1.plot(X[:,0],w[0]*X[:,0]+b[0],"-r",linewidth = 5.0,label = "model") +ax1.legend() +plt.xlabel("x1") +plt.ylabel("y",rotation = 0) + +ax2 = plt.subplot(122) +ax2.scatter(X[:,1],Y[:,0], c = "g",label = "samples") +ax2.plot(X[:,1],w[1]*X[:,1]+b[0],"-r",linewidth = 5.0,label = "model") +ax2.legend() +plt.xlabel("x2") +plt.ylabel("y",rotation = 0) + +plt.show() ``` -### 二,继承Model基类构建自定义模型【面向专家】 +![](./data/3-3-02-回归结果可视化.png) ```python -import tensorflow as tf -from tensorflow.keras import models,layers,optimizers,losses,metrics +``` -#打印时间分割线 -@tf.function -def printbar(): - ts = tf.timestamp() - today_ts = ts%(24*60*60) +```python - hour = tf.cast(today_ts//3600+8,tf.int32)%tf.constant(24) - minite = tf.cast((today_ts%3600)//60,tf.int32) - second = tf.cast(tf.floor(today_ts%60),tf.int32) - - def timeformat(m): - if tf.strings.length(tf.strings.format("{}",m))==1: - return(tf.strings.format("0{}",m)) - else: - return(tf.strings.format("{}",m)) - - timestring = tf.strings.join([timeformat(hour),timeformat(minite), - timeformat(second)],separator = ":") - tf.print("=========="*8,end = "") - tf.print(timestring) - ``` ```python -#样本数量 -n = 800 -# 生成测试用数据集 -X = tf.random.uniform([n,2],minval=-10,maxval=10) -w0 = tf.constant([[2.0],[-1.0]]) -b0 = tf.constant(3.0) +``` -Y = X@w0 + b0 + tf.random.normal([n,1],mean = 0.0,stddev= 2.0) # @表示矩阵乘法,增加正态扰动 +```python +``` + +### 二,DNN二分类模型 + + +此范例我们使用继承Model基类构建自定义模型,并构建自定义训练循环【面向专家】 + + +**1,准备数据** + +```python +import numpy as np +import pandas as pd +from matplotlib import pyplot as plt +import tensorflow as tf +from tensorflow.keras import layers,losses,metrics,optimizers +%matplotlib inline +%config InlineBackend.figure_format = 'svg' + +#正负样本数量 +n_positive,n_negative = 2000,2000 + +#生成正样本, 小圆环分布 +r_p = 5.0 + tf.random.truncated_normal([n_positive,1],0.0,1.0) +theta_p = tf.random.uniform([n_positive,1],0.0,2*np.pi) +Xp = tf.concat([r_p*tf.cos(theta_p),r_p*tf.sin(theta_p)],axis = 1) +Yp = tf.ones_like(r_p) + +#生成负样本, 大圆环分布 +r_n = 8.0 + tf.random.truncated_normal([n_negative,1],0.0,1.0) +theta_n = tf.random.uniform([n_negative,1],0.0,2*np.pi) +Xn = tf.concat([r_n*tf.cos(theta_n),r_n*tf.sin(theta_n)],axis = 1) +Yn = tf.zeros_like(r_n) + +#汇总样本 +X = tf.concat([Xp,Xn],axis = 0) +Y = tf.concat([Yp,Yn],axis = 0) + +#样本洗牌 +data = tf.concat([X,Y],axis = 1) +data = tf.random.shuffle(data) +X = data[:,:2] +Y = data[:,2:] + + +#可视化 +plt.figure(figsize = (6,6)) +plt.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r") +plt.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g") +plt.legend(["positive","negative"]); + +``` + +![](./data/3-3-03-分类数据可视化.png) + +```python ds_train = tf.data.Dataset.from_tensor_slices((X[0:n*3//4,:],Y[0:n*3//4,:])) \ .shuffle(buffer_size = 1000).batch(20) \ .prefetch(tf.data.experimental.AUTOTUNE) \ .cache() ds_valid = tf.data.Dataset.from_tensor_slices((X[n*3//4:,:],Y[n*3//4:,:])) \ - .shuffle(buffer_size = 1000).batch(20) \ + .batch(20) \ .prefetch(tf.data.experimental.AUTOTUNE) \ .cache() ``` ```python -tf.keras.backend.clear_session() -class MyModel(models.Model): +``` + +**2,定义模型** + +```python +tf.keras.backend.clear_session() +class DNNModel(models.Model): def __init__(self): - super(MyModel, self).__init__() + super(DNNModel, self).__init__() def build(self,input_shape): - self.dense1 = layers.Dense(1) - super(MyModel,self).build(input_shape) - - def call(self, x): - y = self.dense1(x) - return(y) - -model = MyModel() + self.dense1 = layers.Dense(4,activation = "relu",name = "dense1") + self.dense2 = layers.Dense(8,activation = "relu",name = "dense2") + self.dense3 = layers.Dense(1,activation = "sigmoid",name = "dense3") + super(DNNModel,self).build(input_shape) + + # 正向传播 + @tf.function(input_signature=[tf.TensorSpec(shape = [None,2], dtype = tf.float32)]) + def call(self,x): + x = self.dense1(x) + x = self.dense2(x) + y = self.dense3(x) + return y + +model = DNNModel() model.build(input_shape =(None,2)) + model.summary() +``` + +``` +Model: "dnn_model" +_________________________________________________________________ +Layer (type) Output Shape Param # +================================================================= +dense1 (Dense) multiple 12 +_________________________________________________________________ +dense2 (Dense) multiple 40 +_________________________________________________________________ +dense3 (Dense) multiple 9 +================================================================= +Total params: 61 +Trainable params: 61 +Non-trainable params: 0 +_________________________________________________________________ +``` + +```python ``` -![](./data/3-3-模型结构.jpg) +**3,训练模型** ```python -### 自定义训练循环(专家教程) +``` + +```python +### 自定义训练循环 -optimizer = optimizers.Adam() -loss_func = losses.MeanSquaredError() +optimizer = optimizers.Adam(learning_rate=0.01) +loss_func = tf.keras.losses.BinaryCrossentropy() train_loss = tf.keras.metrics.Mean(name='train_loss') -train_metric = tf.keras.metrics.MeanAbsoluteError(name='train_mae') +train_metric = tf.keras.metrics.BinaryAccuracy(name='train_accuracy') valid_loss = tf.keras.metrics.Mean(name='valid_loss') -valid_metric = tf.keras.metrics.MeanAbsoluteError(name='valid_mae') +valid_metric = tf.keras.metrics.BinaryAccuracy(name='valid_accuracy') @tf.function @@ -149,8 +325,8 @@ def train_step(model, features, labels): with tf.GradientTape() as tape: predictions = model(features) loss = loss_func(labels, predictions) - gradients = tape.gradient(loss, model.trainable_variables) - optimizer.apply_gradients(zip(gradients, model.trainable_variables)) + grads = tape.gradient(loss, model.trainable_variables) + optimizer.apply_gradients(zip(grads, model.trainable_variables)) train_loss.update_state(loss) train_metric.update_state(labels, predictions) @@ -172,27 +348,70 @@ def train_model(model,ds_train,ds_valid,epochs): for features, labels in ds_valid: valid_step(model,features,labels) - logs = 'Epoch={},Loss:{},MAE:{},Valid Loss:{},Valid MAE:{}' + logs = 'Epoch={},Loss:{},Accuracy:{},Valid Loss:{},Valid Accuracy:{}' if epoch%100 ==0: printbar() tf.print(tf.strings.format(logs, (epoch,train_loss.result(),train_metric.result(),valid_loss.result(),valid_metric.result()))) - tf.print("w=",model.layers[0].kernel) - tf.print("b=",model.layers[0].bias) - tf.print("") train_loss.reset_states() valid_loss.reset_states() train_metric.reset_states() valid_metric.reset_states() -train_model(model,ds_train,ds_valid,400) +train_model(model,ds_train,ds_valid,1000) +``` ``` +================================================================================17:35:02 +Epoch=100,Loss:0.194088802,Accuracy:0.923064,Valid Loss:0.215538561,Valid Accuracy:0.904368 +================================================================================17:35:22 +Epoch=200,Loss:0.151239693,Accuracy:0.93768847,Valid Loss:0.181166962,Valid Accuracy:0.920664132 +================================================================================17:35:43 +Epoch=300,Loss:0.134556711,Accuracy:0.944247484,Valid Loss:0.171530813,Valid Accuracy:0.926396072 +================================================================================17:36:04 +Epoch=400,Loss:0.125722557,Accuracy:0.949172914,Valid Loss:0.16731061,Valid Accuracy:0.929318547 +================================================================================17:36:24 +Epoch=500,Loss:0.120216407,Accuracy:0.952525079,Valid Loss:0.164817035,Valid Accuracy:0.931044817 +================================================================================17:36:44 +Epoch=600,Loss:0.116434008,Accuracy:0.954830289,Valid Loss:0.163089141,Valid Accuracy:0.932202339 +================================================================================17:37:05 +Epoch=700,Loss:0.113658346,Accuracy:0.956433,Valid Loss:0.161804497,Valid Accuracy:0.933092058 +================================================================================17:37:25 +Epoch=800,Loss:0.111522928,Accuracy:0.957467675,Valid Loss:0.160796657,Valid Accuracy:0.93379426 +================================================================================17:37:46 +Epoch=900,Loss:0.109816991,Accuracy:0.958205402,Valid Loss:0.159987748,Valid Accuracy:0.934343576 +================================================================================17:38:06 +Epoch=1000,Loss:0.10841465,Accuracy:0.958805501,Valid Loss:0.159325734,Valid Accuracy:0.934785843 +``` + +```python -![](./data/3-3-自定义训练.jpg) +``` +```python +# 结果可视化 +fig, (ax1,ax2) = plt.subplots(nrows=1,ncols=2,figsize = (12,5)) +ax1.scatter(Xp[:,0].numpy(),Xp[:,1].numpy(),c = "r") +ax1.scatter(Xn[:,0].numpy(),Xn[:,1].numpy(),c = "g") +ax1.legend(["positive","negative"]); +ax1.set_title("y_true"); + +Xp_pred = tf.boolean_mask(X,tf.squeeze(model(X)>=0.5),axis = 0) +Xn_pred = tf.boolean_mask(X,tf.squeeze(model(X)<0.5),axis = 0) + +ax2.scatter(Xp_pred[:,0].numpy(),Xp_pred[:,1].numpy(),c = "r") +ax2.scatter(Xn_pred[:,0].numpy(),Xn_pred[:,1].numpy(),c = "g") +ax2.legend(["positive","negative"]); +ax2.set_title("y_pred"); +``` + +![](./data/3-3-04-分类结果可视化.png) + +```python + +``` 如果对本书内容理解上有需要进一步和作者交流的地方,欢迎在公众号"Python与算法之美"下留言。作者时间和精力有限,会酌情予以回复。 diff --git "a/data/3-1-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" "b/data/3-1-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..da05b608 Binary files /dev/null and "b/data/3-1-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-1-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" "b/data/3-1-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..ee418160 Binary files /dev/null and "b/data/3-1-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-1-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" "b/data/3-1-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..fa2767fa Binary files /dev/null and "b/data/3-1-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-1-2-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" "b/data/3-1-2-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..ea7fcaad Binary files /dev/null and "b/data/3-1-2-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-2-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" "b/data/3-2-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..f7da8ae4 Binary files /dev/null and "b/data/3-2-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-2-02-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" "b/data/3-2-02-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..632d8051 Binary files /dev/null and "b/data/3-2-02-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-2-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" "b/data/3-2-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..6e13ea17 Binary files /dev/null and "b/data/3-2-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-2-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" "b/data/3-2-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..a0073684 Binary files /dev/null and "b/data/3-2-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-3-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" "b/data/3-3-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..47e70f44 Binary files /dev/null and "b/data/3-3-01-\345\233\236\345\275\222\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-3-02-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" "b/data/3-3-02-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..539c2503 Binary files /dev/null and "b/data/3-3-02-\345\233\236\345\275\222\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-3-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" "b/data/3-3-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..9cb0b1b8 Binary files /dev/null and "b/data/3-3-03-\345\210\206\347\261\273\346\225\260\346\215\256\345\217\257\350\247\206\345\214\226.png" differ diff --git "a/data/3-3-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" "b/data/3-3-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" new file mode 100644 index 00000000..392aa4f9 Binary files /dev/null and "b/data/3-3-04-\345\210\206\347\261\273\347\273\223\346\236\234\345\217\257\350\247\206\345\214\226.png" differ diff --git a/push-to-github.py b/push-to-github.py index ca5a6c4c..a01f7c0d 100644 --- a/push-to-github.py +++ b/push-to-github.py @@ -29,7 +29,7 @@ # !git push origin master -# !git push gitee master +# !git push gitee master # ## 创建pages分支 diff --git "a/\344\270\211\343\200\201TensorFlow\347\232\204\345\261\202\346\254\241\347\273\223\346\236\204.md" "b/\344\270\211\343\200\201TensorFlow\347\232\204\345\261\202\346\254\241\347\273\223\346\236\204.md" index a30987b8..33fefb05 100644 --- "a/\344\270\211\343\200\201TensorFlow\347\232\204\345\261\202\346\254\241\347\273\223\346\236\204.md" +++ "b/\344\270\211\343\200\201TensorFlow\347\232\204\345\261\202\346\254\241\347\273\223\346\236\204.md" @@ -1,7 +1,7 @@ # 三、TensorFlow的层次结构 -本章我们介绍TensorFlow中5个不同的层次结构:即硬件层,内核层,低阶API,中阶API,高阶API。并以线性回归为例,直观对比展示在不同层级实现模型的特点。 +本章我们介绍TensorFlow中5个不同的层次结构:即硬件层,内核层,低阶API,中阶API,高阶API。并以线性回归和DNN二分类模型为例,直观对比展示在不同层级实现模型的特点。 TensorFlow的层次结构从低到高可以分成如下五层。