# Tensorflow 基础框架

# 处理结构

计算图纸

Tensorflow 首先要定义神经网络的结构,然后再把数据放入结构当中去运算和 training.

处理结构

因为 TensorFlow 是采用数据流图(data flow graphs)来计算,所以首先我们得创建一个数据流流图,然后再将我们的数据(数据以张量 (tensor) 的形式存在)放在数据流图中计算。节点(Nodes)在图中表示数学操作,图中的线(edges)则表示在节点间相互联系的多维数据数组,即张量(tensor). 训练模型时 tensor 会不断的从数据流图中的一个节点 flow 到另一节点,这就是 TensorFlow 名字的由来.

# 例子 1

tensorflow version 1 代码如下

import tensorflow as tf
import numpy as np
# create data
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data*0.1 + 0.3
#搭建模型
Weights = tf.Variable(tf.random_uniform([1], -1.0, 1.0))
biases = tf.Variable(tf.zeros([1]))
y = Weights*x_data + biases
#计算误差
loss = tf.reduce_mean(tf.square(y-y_data))
#传播误差
#反向传递误差的工作就教给 optimizer 了,我们使用的误差传递方法是梯度下降法: Gradient Descent 让后我们使用 optimizer 来进行参数的更新.
optimizer = tf.train.GradientDescentOptimizer(0.5)
train = optimizer.minimize(loss)
#训练
#到目前为止,我们只是建立了神经网络的结构,还没有使用这个结构。在使用这个结构之前,我们必须先初始化所有之前定义的 Variable, 所以这一步是很重要的!
# init = tf.initialize_all_variables () # tf 马上就要废弃这种写法
init = tf.global_variables_initializer()  # 替换成这样就好
#接着,我们再创建会话 Session. 我们用 Session 来执行 init 初始化步骤。并且,用 Session 来 run 每一次 training 的数据。逐步提升神经网络的预测准确性.
sess = tf.Session()
sess.run(init)          # Very important
for step in range(201):
    sess.run(train)
    if step % 20 == 0:
        print(step, sess.run(Weights), sess.run(biases))

tensorflow version 2 代码如下

import tensorflow as tf
import numpy as np
#creat data
x_data = np.random.rand(100).astype(np.float32)
y_data = x_data*01.+0.3
### creat tensorflow structure start ###
Weights = tf.Variable(tf.random.uniform((1,),-1.0,1.0))
biases = tf.Variable(tf.zeros([1]))
y = Weights*x_data+biases
loss= lambda: tf.keras.losses.MSE(y_data,Weights * x_data +biases)
optimizer = tf.keras.optimizers.SGD(learning_rate=0.5)
### creat tensorflow structure end ###
for step in range(201):
    optimizer.minimize(loss, var_list=[Weights, biases])
    if step %20==0:
        #print(step,sess.run(Weights),sess.run(biases))
        print("{} step, weights = {}, biases = {}".format(step, Weights.read_value(), biases.read_value()))  # read_value 函数可用 numpy 替换

# Session 会话控制

这一次我们会讲到 Tensorflow 中的 Session , Session 是 Tensorflow 为了控制,和输出文件的执行的语句。运行 session.run() 可以获得你要得知的运算结果,或者是你所要运算的部分.

首先,我们这次需要加载 Tensorflow ,然后建立两个 matrix , 输出两个 matrix 矩阵相乘的结果。

import tensorflow as tf
# create two matrixes
matrix1 = tf.constant([[3,3]])
matrix2 = tf.constant([[2],
                       [2]])
product = tf.matmul(matrix1,matrix2)

因为 product 不是直接计算的步骤,所以我们会要使用 Session 来激活 product 并得到计算结果。有两种形式使用会话控制 Session

# method 1
sess = tf.Session()
result = sess.run(product)
print(result)
sess.close()
# [[12]]
# method 2
with tf.Session() as sess:
    result2 = sess.run(product)
    print(result2)
# [[12]]

tensorflow version 2 已经不需要用 session 控制了

import tensorflow as tf
matrix1=tf.constant([[3,3]])
matrix2=tf.constant([[2],[2]])
product=tf.matmul(matrix1,matrix2)
tf.print(product)

# Variable 变量

在 Tensorflow 中,定义了某字符串是变量,它才是变量,这一点是与 Python 所不同的。

定义语法: state = tf.Variable()

import tensorflow as tf
state = tf.Variable(0, name='counter')
# 定义常量 one
one = tf.constant(1)
# 定义加法步骤 (注:此步并没有直接计算)
new_value = tf.add(state, one)
# 将 State 更新成 new_value
update = tf.assign(state, new_value)

如果你在 Tensorflow 中设定了变量,那么初始化变量是最重要的!!所以定义了变量以后,一定要定义 init = tf.initialize_all_variables() .

到这里变量还是没有被激活,需要再在 sess 里, sess.run(init) , 激活 init 这一步.

# 如果定义 Variable, 就一定要 initialize
init = tf.global_variables_initializer()  # 替换成这样就好
 
# 使用 Session
with tf.Session() as sess:
    sess.run(init)
    for _ in range(3):
        sess.run(update)
        print(sess.run(state))

注意:直接 print(state) 不起作用!!

一定要把 sess 的指针指向 state 再进行 print 才能得到想要的结果!

附上 v2 代码

import tensorflow as tf
state=tf.Variable(0,name='counter')
one=tf.constant(1)
new_value=tf.add(state,one)
for _ in range(3):
	#The variable value can be changed using one of the assign methods.
	state.assign_add(new_value)
	tf.print(state,new_value)

# Placeholder 传入值

placeholder 是 Tensorflow 中的占位符,暂时储存变量.

Tensorflow 如果想要从外部传入 data, 那就需要用到 tf.placeholder() , 然后以这种形式传输数据 sess.run(***, feed_dict={input: **}) .

示例:

import tensorflow as tf
#在 Tensorflow 中需要定义 placeholder 的 type ,一般为 float32 形式
input1 = tf.placeholder(tf.float32)
input2 = tf.placeholder(tf.float32)
# mul = multiply 是将 input1 和 input2 做乘法运算,并输出为 output 
ouput = tf.multiply(input1, input2)

接下来,传值的工作交给了 sess.run() , 需要传入的值放在了 feed_dict={} 并一一对应每一个 input . placeholderfeed_dict={} 是绑定在一起出现的。

with tf.Session() as sess:
    print(sess.run(ouput, feed_dict={input1: [7.], input2: [2.]}))
# [ 14.]

v2 貌似已经换掉了 placeholder ,看到我再添加。

# Activation Function 激励函数

这里的 AF 就是指的激励函数。激励函数拿出自己最擅长的” 掰弯利器”, 套在了原函数上 用力一扭,原来的 Wx 结果就被扭弯了.

其实这个 AF, 掰弯利器,也不是什么触不可及的东西。它其实就是另外一个非线性函数。比如说 relu, sigmoid, tanh. 将这些掰弯利器嵌套在原有的结果之上,强行把原有的线性结果给扭曲了。使得输出结果 y 也有了非线性的特征。举个例子,比如我使用了 relu 这个掰弯利器,如果此时 Wx 的结果是 1, y 还将是 1, 不过 Wx 为 - 1 的时候,y 不再是 - 1, 而会是 0.

你甚至可以创造自己的激励函数来处理自己的问题,不过要确保的是这些激励函数必须是可以微分的,因为在 backpropagation 误差反向传递的时候,只有这些可微分的激励函数才能把误差传递回去.

想要恰当使用这些激励函数,还是有窍门的。比如当你的神经网络层只有两三层,不是很多的时候,对于隐藏层,使用任意的激励函数,随便掰弯是可以的,不会有特别大的影响。不过,当你使用特别多层的神经网络,在掰弯的时候,玩玩不得随意选择利器。因为这会涉及到梯度爆炸,梯度消失的问题。因为时间的关系,我们可能会在以后来具体谈谈这个问题.

最后我们说说,在具体的例子中,我们默认首选的激励函数是哪些。在少量层结构中,我们可以尝试很多种不同的激励函数。在卷积神经网络 Convolutional neural networks 的卷积层中,推荐的激励函数是 relu. 在循环神经网络中 recurrent neural networks, 推荐的是 tanh 或者是 relu (这个具体怎么选,我会在以后 循环神经网络的介绍中在详细讲解).

# 创建第一个神经网络

# 例子 3 添加层 def add_layer ()

# 计算机视觉介绍

# Anaconda 使用

%config IPCompleter.greedy=True  #按 tag 可以自动补全代码

# 加载 Fashion MNIST 数据集

70000 张图片
10 个类别
28*28 像素
训练神经元网络
image-20201209220451516

import tensorflow as tf
from tensorflow import keras
import matplotlib.pyplot as plt
#导入数据集
fasion_mnist = keras.datasets.fashion_mnist
#划分数据集
(train_images,train_labels),(test_images,test_labels) = fasion_mnist.load_data()
#看数据集大小
print(train_images.shape)
#展示图片
plt.imshow(train_images[1])

image-20201209220813905

# 构建神经元网络模型

image-20201209220900053

image-20201209220929783

全连接的网络结构

model = keras.Sequential()
model.add(keras.layers.Flatten(input_shape=(28,28)))
model.add(keras.layers.Dense(128,activation=tf.nn.relu))
model.add(keras.layers.Dense(10,activation=tf.nn.softmax))
model.summary()
#以下为 console
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten_1 (Flatten)          (None, 784)  个像素             0         
_________________________________________________________________
dense (Dense)                (None, 128)               100480784个像素+1权重)*128个神经元
_________________________________________________________________
dense_1 (Dense)              (None, 10)                1290128个神经元+1权重)*10个类别
=================================================================
Total params: 101,770
Trainable params: 101,770
Non-trainable params: 0
_________________________________________________________________

# 训练和评估模型

#scaling or normalization 把灰度变成只有 1 和 0
train_imges_scaled=train_images/255
#metrics=['accuracy'] 是为了看到指标 accuracy 的变化,
model.compile(optimizer=tf.optimizers.Adam(),loss=tf.losses.sparse_categorical_crossentropy,metrics=['accuracy'])
#训练,epochs 重复次数 5 次
model.fit(train_imges_scaled,train_labels,epochs=5)
#模型评估
test_images_scaled = test_images/255
model.evaluate(test_images_scaled,test_labels)
import numpy as np
print(np.argmax( model.predict([[test_images[0]/255]])))
print(test_labels[0])
plt.imshow(test_images[0])

# 自动终止训练

image-20201210194942305

#重载一个 callback 方法
class myCallback(tf.keras.callbacks.Callback):
    def on_epoch_end(self,epoch,logs={}):
        if(logs.get('loss')<0.4):
            print("\n Loss is low so cancelling training!")
            self.model.stop_training = True
            
callbacks= myCallback()
mnist =tf.keras.datasets.fashion_mnist
(training_images,training_labels),(test_images,test_labels) = mnist.load_data()
training_images_scaled = training_images/255
test_images_scaled = test_images/255
model =tf.keras.models.Sequential([
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(512,activation = tf.nn.relu),
    tf.keras.layers.Dense(10,activation = tf.nn.softmax)
])
model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])
model.fit(training_images_scaled,training_labels,epochs=5,callbacks=[callbacks])
---console:---
Epoch 1/5
1875/1875 [==============================] - 5s 3ms/step - loss: 0.4734 - accuracy: 0.8292
Epoch 2/5
1867/1875 [============================>.] - ETA: 0s - loss: 0.3585 - accuracy: 0.8697
 Loss is low so cancelling training!
1875/1875 [==============================] - 5s 3ms/step - loss: 0.3583 - accuracy: 0.8697
-->