tensorflow学习笔记

tensorflow模型训练

神经元模型

计算机神经元模型由
1.神经元

2.权重

3.偏差值组成

神经网络和深度学习的关系

在人工智能领域中,最常用的基础模型有三个
1.全链接神经网络:最基础的神经网络之一,用来处理与数值相关的任务
2.卷积神经网络:常用来处理与计算机视觉相关的任务
3.循环神经网络:常用来处理与序列相关的任务

整个神经网络的几何意义

在复杂的全链接神经网络中,随着输入节点增加,模型的几何意义甚至会从二位上升到多位

隐藏层的几何意义

根据权重和偏差值的不断修正,我们最后会获得一个范围

离散微积分

离散微分和离散积分

细分的过程被叫做离散微分
在计算机神经网络中,

我们把图片进行数字化处理,
将图片变为矩阵,矩阵中的每一个值都是0-255之间的值

代表图片的一个像素点

其工作模式与人脑类似,具体步骤为

1.利用卷积操作对图片局部信息惊喜处理,生成低级特征,再拓展至多个低级特征

2.对低级特征执行多次卷积操作,生成中极特征,高级特征

3.将多个局部信息的高级特征组合到一起,生成最终的结束结果

卷积神经网络

卷积神经网络使计算机视觉领域中最常用的神经网络之一,它使用了比全链接网络更小的权重,对数据进行居于区域的小规模运算,这种做法可以使用更少的权重完成对数据的分类任务,也改善了训练时候难以收敛的状况,并且提高了模型的泛化能力

下面来讲一下卷积的过程(cnn)

1 卷积运算

首先我们需要知道什么是卷积计算,它其实是一种简单数学运算,有两个步骤:一个是矩阵内积乘法,另一个是将内积乘法的结果进行全加。

(1)矩阵内积乘法

矩阵的内积乘法非常简单,就是把两个相乘的矩阵,相同位置的元素进行乘法运算,这个时候会得到一个新的矩阵(在这里我们需要注意一下,卷积是在作矩阵内积乘法,而不是矩阵乘法)。

(2)全加计算

这个新矩阵的全部值会进行相加,然后会得到一个值,这个值才是卷积运算的结果。

不太好表达,但是理解就行,有点类似于小时候《冒险小虎队》的解密卡内种感觉

不同的步长也可以产生不同的新矩阵

如果忘记了:https://zhuanlan.zhihu.com/p/52340698

看看这里 这片文章是讲2d卷积的

1d卷积平常用来处理文本特征数值相关的数据

2d卷积用来处理平面图片类数据

3d用来处理立体图像和视频类数据

emm有个经典案例就是sobel算子

sobel算子有两套权重方案,分别沿着图片水平和垂直方向边缘检测

而在深度神经网络中

有很多类似于sobel算子的卷积核

他们说通过大量样本训练后算出来的

在训练过程中,会根据最终输出结果调节卷积核的权重,最终生产出若干个有特定功能的卷积核

多次执行卷积的特征数据会更具有局部特征,比如可以识别出眼睛鼻子嘴巴,不同的卷积核对图片进行推理和叠加,最终完成对整张图片的识别

反卷积

反卷积可以理解为卷积操作中的逆操作

卷积分

卷积分是积分的一种计算方式

通俗点说就是把一条函数作为系数矩阵,另一条函数当初卷积核

\[y=3x+2 \]

\[y=2x^2+3x-1 \]

函数1的矩阵就是 0 0 3 2

将卷积核 1 3 2 对其依次卷积

如果还不够通俗,从代数的角度出发看就是

这两个函数香橙

\[y=(3x+2)(2x^2+3x-1)=6x^3+13x^2+3x-2 \]

卷积神经网络和全链接神经网络的关系

如果多个全尺寸的卷积核按照不同层次组合在一起,相当于多个神经元的组合,那么这个卷积神经网络就变成了全链接神经网络

升纬和降维

一般我们会使用1*1卷积核进行升维和降维

假如有一个

\[28*28*192 \]

的矩阵,如果我们直接用[5,5,32]进行卷积,计算量

大约有1.2亿次

如果使用[1,1,16]先降维一个阶段,再用[5,5,32]进行卷积

就只需要大约1200万的计算量,可以节约十倍的算力

残差网络 ResNet

残差网络的信息传递基本上很少有损失的,因为下一层都能看到前一层的所有数据

tensorflow.keras接口

keras有是由python语言编写的神经网络api

主要由三个特点

1.对用户友好,模块化,可拓展

2.支持卷积神经网络,循环神经网络

3.无缝支持cpu和gpu

Tensorflow2的模块

disable_v2_behavior

tf2居然还内置了tf1的方法,我们要对静态图进行处理的话,静态图是tf1版本的主要运行方式

decode_jpeg

同样也是tf1的用法,用法是

tf.image.decode_jpeg(tf.compat.v1.decode_base64(input_imgs), channels=3)

这个channel是通道的意思

使用模型时预处理输入图片

Tensorflow封装的调节图片尺寸算法一共有四种

双线性插值法

双线性插值法分别在两格方向进行先行插值以及计算新图像上对应点的像素值,在计算时候只用原始图像中的四个像素点来计算当前的心像素值

tensorflow中双线性插值发的代码实现如下

tf.compat.v1.image.resize_image(images,size,method=ResizeMethod.BILINEAR,align_coners=False,
                               preserve_aspect_ratio=False)

最近邻法

最近邻法双一种调整图片尺寸的方法,基本原理双新图像的像素值等于原始图像中距离它最近的像素值

tf.compat.v1.image.resize_images(images,size,method=tf.image.ResizeMethod.NEAREST_NEIGHBOR)

两三次插值法

双三次插值法分别在两格方向进行三次插值以计算新图像上对应点的像素值,通常使用拉格朗日多项式或三次样条函数

https://www.bilibili.com/video/BV1ZC4y1p77B/

拉格朗日插值法概念在这里

三次样条函数 还未找到,不过看大体和拉格朗日差不多

tf.compat.v1.image.resize_image(images,size,method=ResizeMethod.BICUBIC,align_coners=False,
                               preserve_aspect_ratio=False)

面积插值法

面积插值法也称做区域插值法,该方法首先把原始图像分割成不同区域,然后把输出图像中的插值点映射到输入图像病判断所属区域,最后计算与插值点相交的像素点加权平均数,加权重上相交的面积比例

tf.compat.v1.image.resize_image(images,size,method=ResizeMethod.AREA,align_coners=False,
                               preserve_aspect_ratio=False)

数据预处理的重要性

在使用模型的场景下,数据的预处理一定要与训练模型时候使用的与训练方法一直,只有这样才会重复发挥模型的作用,这也是训练时候需要特别注意的地方

saved_model用法

​ 为了让生成的模型支持TF_Serving【云端模型服务】tf对模型前面进行了统一规定

模型的分类任务签名:

CLASSIFY_METHOD_NAME

输入 :

CLASSIFY_INPUTS("inputs")

输出:

CLASSIFY_OUTPUT_CLASSES("classes")#分类结果
CLASSIFY_OUTPUT_SCORES("scores")#分类概率

预测任务签名:

PREDICT_METHOD_NAME("tensor flow/serving/predict")

输入:

PREDICT_INPUTS("inputs")

输出:

PREDICT_OUTPUTS("outputs")

回归任务签名:

REGRESS_METHOD_NAME("tensor flow/serving/regress")

输入:

REGRESS_INPUTS("inputs")

输出:

REGRESS_OUTPUTS("outputs")

以及一个默认的接口签名用于拓展:

DEFAULT_SERVING_SIGNATURE_DEF_KEY("serving_default")

代码示例

    save_path = './model'  # 设置模型保存路径
    # 创建用于保存模型的builder对象
    builder = tf.compat.v1.saved_model.builder.SavedModelBuilder(save_path + 'imgclass')

    # 定义输入签名,X为输入张量
    inputs = {'input_x': tf.compat.v1.saved_model.utils.build_tensor_info(input_imgs)}
    # 定义输出签名, z为最终需要的输出结果张量
    outputs = {'output': tf.compat.v1.saved_model.utils.build_tensor_info(prediction)}
    signature = tf.compat.v1.saved_model.signature_def_utils.build_signature_def(
        inputs=inputs,
        outputs=outputs,
        method_name=tf.compat.v1.saved_model.signature_constants.PREDICT_METHOD_NAME)

    # 将节点的定义和值加到builder中,同时还加入了标签, 还可以使用TRAINING、GPU或自定义
    builder.add_meta_graph_and_variables(sess, [tf.compat.v1.saved_model.tag_constants.SERVING],
                                         {'aianaconda_signature': signature})
    builder.save()  # 保存模型

VGG模型

Visual Geometry Group Network

视觉几何组网络模型

特点是采用连续的几个3x3的卷积核代替较大的卷积核

卷积层

卷积层:每一个卷积核都是3×3。vgg-block内的卷积层都是同结构的。意味着输入和输出的尺寸一样,且卷积层可以堆叠复用

池化层

池化层:maxpool层将前一层(vgg-block层)的特征缩减一半,使得尺寸缩减的很规整,从224-112-56-28-14-7。

池化层只能用2x2的最大池化层

池化就是对矩阵使用一个2x2对filter 步长为2进行扫描,

MaxPooling

选择最大值输出到下一层

AveragePooling

选择平均值输出到下一层

卷积可代替全连接,可适应各种尺寸的图片

v2-5e7d7aa2620cd7e2f732912f467c3cc5_b

inception

是google公司与2014年提出的卷积神经网络

前生是googlenet

v3

v3把用两格3x3的卷积核代替原始inception的5x5卷积核

而沿着这个思路继续思考

又能提出一种新的卷积分解

把33的卷积分解为13和31的卷积

理论上

\[n^2 \]

的卷积都可以分解为1xn 和nx1卷积

爬虫篇

数据分析肯定需要数据源

那我们的数据源就是爬虫

不过没什么好说的,skip

样本载入数据集

通俗的说就是把图片转化成矩阵

tf.data.Dataset接口

这是tensorflow主推的数据传入接口

使用的时候调用此接口回生成一个dataset对象

训练时候该接口会执行以下操作

1.读取数据

2.预处理数据

3.创建dataset对象

4.调用dataset对象的类方法,对数据集中的数据执行乱序,组合,复用,缓存等操作

具体用法在书上第73页到77页

一般来说,处理数据集比较合理的步骤为

1.创建数据集

2.使数据集乱序(shuffle

3.重复数据集(repeat

4.变换数据集中的元素

5.指定批次(batch

6.指定缓冲区

tf.keras接口

是用tensorflow实现keras的一系列高级接口

使用tf.keras有两种模式。调用函数API模式和构建子类模式

调用接口函数

import numpy as np
import random
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense

# 生成随机训练数据
x_train = np.linspace(0, 10, 100)  # 100 evenly spaced numbers from 0 to 10
y_train_random = -1 + 2 * np.random.random(100)  # 100 random numbers between -1 and 1
y_train = 2 * x_train + y_train_random  # y=2x+noise
print("x_train\n", x_train)  # print the x_train array
print("y_train\n", y_train)  # print the y_train array

# This returns a tensor
x_test = np.linspace(0, 10, 100)  # 100 evenly spaced numbers from 0 to 10
y_test_random = -1 + 2 * np.random.random(100)  # 100 random numbers between -1 and 1
y_test = 2 * x_test + y_test_random  # y=2x+noise
print("x_test\n", x_test)  # print the x_test array
print("y_test\n", y_test)  # print the y_test array

x_predict = random.sample(range(0, 10), 10)  # 10 random numbers between 0 and 10

inputs = Input(shape=(1,))  # 生成一个输入层,输入维度为1

# 生成一个全连接层,输出维度为1
inputs = Input(shape=(1,))
x = Dense(64, activation='relu')(inputs)  # 64个神经元,激活函数为relu
x = Dense(64, activation='relu')(x)  # 64个神经元,激活函数为relu
predictions = Dense(1)(x)  # 输出维度为1
model = Model(inputs=inputs, outputs=predictions)  # 生成模型
model.compile(optimizer='rmsprop',  # 优化器
              loss='mse',  # 损失函数为均方误差
              metrics=['mae'])  # 损失函数为均方误差,评价指标为平均绝对误差

# 训练模型,指定训练参数
history = model.fit(x_train,
                    y_train,
                    epochs=100,  # 训练轮数
                    batch_size=16)  # 每批训练样本数

#测试模型
score =model.evaluate(x_test, y_test, batch_size=16) # 测试模型,返回损失值和评价指标
print("score \n",score) # 打印损失值和评价指标

# 预测
y_predict = model.predict(x_predict)  # 预测
print("x_predict \n", x_predict)  # 打印预测输入
print("y_predict \n", y_predict)  # 打印预测结果

构建子类的方式

import tensorflow as tf  # 导入基础模块
import tensorflow.keras as keras  # 导入keras模块
import numpy as np  # 导入numpy模块
from tensorflow.keras.models import Model  # 导入模型
from tensorflow.keras.layers import Input, Dense,Layer  # 导入输入层和全连接层
import random # 导入随机数模块

#调用子类
class MyLayer(Layer):
    def __init__(self, output_dim, **kwargs):  # 初始化函数
        self.output_dim = output_dim  # 输出维度
        super(MyLayer, self).__init__(**kwargs)  # 调用父类初始化函数
    def build(self, input_shape):    # 构建函数

        self.kernel = self.add_weight(name='kernel',  # 添加权重
                                      shape=(input_shape[1], self.output_dim),  # 权重形状
                                      initializer='uniform',  # 权重初始化方法
                                      trainable=True)  # 权重是否可训练
        super(MyLayer, self).build(input_shape)    # 调用父类构建函数
    def call(self, inputs):  # 前向传播函数
        return tf.matmul(inputs, self.kernel)  # 矩阵乘法
    def compute_output_shape(self, input_shape): # 计算输出形状函数
        shape=tf.TensorShape(input_shape).as_list() # 将输入形状转换为列表
        shape[-1]=self.output_dim # 将输出维度赋值给列表最后一个元素
        return tf.TensorShape(shape) # 返回输出形状

    def get_config(self):  # 获取配置函数
        base_config= super(MyLayer, self).get_config()  # 调用父类获取配置函数
        base_config['output_dim']=self.output_dim  # 添加输出维度到配置字典
        return base_config  # 返回配置字典

    @classmethod
    def from_config(cls, config):
        return cls(**config)

#测试程序
if __name__ == '__main__':
    #生成训练数据 y=2x
    x_train = np.linspace(0, 10, 100)  # 100 evenly spaced numbers from 0 to 10
    y_train_random= -1 + 2 * np.random.random(100)  # 100 random numbers between -1 and 1
    y_train = 2 * x_train + y_train_random  # y=2x+noise
    print("x_train\n", x_train)
    print("y_train\n", y_train)

    #生成测试数据
    x_test = np.linspace(0, 10, 100)  # 100 个数
    y_test_random= -1 + 2 * np.random.random(100)  # 100 random numbers between -1 and 1
    y_test = 2 * x_test + y_test_random  # y=2x+noise
    print("x_test\n", x_test)
    print("y_test\n", y_test)

    x_predict=random.sample(range(0,10),10) # 生成10个随机数 用于预测

    inputs= Input(shape=(1,))  # 输入层 1个神经元
    x=Dense(64,activation='relu')(inputs)  # 隐藏层 64个神经元 激活函数为relu
    x=MyLayer(64)(x)  # 隐藏层 64个神经元
    predictions=Dense(1)(x)  # 输出层 1个神经元

    #编译模型
    model=Model(inputs=inputs,outputs=predictions)  # 实例化模型
    model.compile(optimizer='rmsprop',loss='mse',metrics=['mae'])  # 编译模型

    history=model.fit(x_train,y_train,epochs=1000,batch_size=16)  # 训练模型
    score=model.evaluate(x_test,y_test,batch_size=16)  # 评估模型

    print("score\n",score)  # 打印评估结果

    y_predict=model.predict(x_predict)  # 预测
    print("x_predict\n",x_predict)  # 打印预测输入
    print("y_predict\n",y_predict)  # 打印预测结果

深度卷积神经网络的概念

卷积神经网络的组成

由卷积层,池化层,全链接层(或者全局平均池化层)组成

卷积操作公式都已经烂熟于心

池化运算

池化云散就是拿一个池化核比如2x2 3x3的核在矩阵上扫描

区别在于

卷积是相加 而池化会根据我的需求取最大值或取平均值

ReLU函数激活

最后是激活relu函数

relu经常放在池化层之后

说人话就是一元一次方程

局限性

relu有局限性

就是如果预测的东西是负向传播的

很容易把所有值都剥夺

输出0,那么这个模型就无法训练了

所以我们找到了一个类似的relu变体

softplus

虽然softplus理论上比relu效果好

但是消耗的算力特别大,因此我们基本上还是会使用relu函数

Dropout层

dropout的实现过程是在训练时候按照一定概率丢弃网络层中的一些神经元,让他们不用参加训练,在下一轮迭代中不更新他们的权重和偏执值

可以理解为使用预测结果中多个训练过程中子网络的合集

softmax算法

多分类神经网络输出层中一般作为最后一层用于输出结果

经过softmax算法吹后的特征值都会变成0-1之间的小数

这些小数的总和为1
因此如果判断属于某一打雷的概率高于其他类,那么这个值就会逼近于1

其他值就逼近0

\[Softmax=e^Logits/reduce_sum(e^Logits,dim) \]

e约等于2.718

主要用于让预测结果更加准确

构建网络模型

posted @ 2023-03-16 18:05  是我,米老鼠  阅读(56)  评论(0编辑  收藏  举报