Python深度学习基于Tensorflow(2)Tensorflow基础

news2024/11/24 16:57:49

文章目录

      • 基本操作
        • 数据转换和数据生成
        • 操作形状
        • 数据提取和保存
        • 变量
        • Numpy和Tensorflow的比较
      • 计算图
        • 静态图
        • 动态图
        • 自动图
      • 自动微分
      • 使用Tensorflow 实现回归

首先是Tensorflow的安装,由于可能会出现版本冲突,最好在conda环境安装,同时,目前windows版本好像只支持2.10,更高的版本目前只支持linux系统。

conda 安装, 配置以及使用_conda安装配置-CSDN博客
23.10.02更新 windows系统下的Tensorflow安装(图多详细)_windows 安装tensorflow-CSDN博客
23.10.02更新 Windows下CUDA和CUDNN的安装和配置(图多详细)_cuda百度云-CSDN博客

GPU涉及到显卡,这里可以在命令行输入nvidia-smi获取GPU信息

![[Pasted image 20240506143247.png]]

安装顺序为:查看显卡信息 -> 安装CUDA,CUDNN -> 安装Tensorflow GPU版

list 在 numpy 中叫 ndarray,在 tensorflow 中叫 tensor,其性能上的主要区别是:ndarray只能在CPU上计算,而tensorflow不仅可以在CPU上计算,也可以在GPU/TPU上计算。

tensor 和 numpy 一样,有三个属性:TensorObject.ndim、 TensorObject.shape、 TensorObject.dtype。分别表示数据维度,数据形状,数据类型。只需要在tensor后面加一个numpy(),如:TensorObject.numpy()。就可以很轻松的将tensor转化为numpy。

import tensorflow as tf

基本操作

数据转换和数据生成

首先是将已有数据转化为tensor,其中tensor有两种,一种是常数,一种是变量,其中常数是不可以对数值进行更改的,而变量的值是可以更改的。

lst = [1.123, 2.333, 4.12212] 

# 获得常数
tensor = tf.constant(lst)
# 获得变量
tensor_variable = tf.Variable(lst)
## 更改变量
tensor_variable.assign([1.3,1.3,1.3])

# tensor转换为numpy
array = tensor.numpy()

# numpy转化为tensor
tensor = tf.constant(array)
tensor_variable = tf.Variable(array)
tensor = tf.convert_to_tensor(array)

# 拓展:创建不规则张量
tensor = tf.ragged.constant([
    [0, 1, 2, 3],
    [4, 5],
    [6, 7, 8],
    [9]])

数据生成主要是random,range,linspace;这三个函数对应于numpy中的random,arange,linspace

## range 生成0-100之间步长为3的tensor
tf.range(0,100,3)

## linspace 在0-100之间等距离生成3个数的tensor
tf.linspace(0,100,3)

## random示例:normal 生成形状为[10,20]的正态分布矩阵
tf.random.normal(shape=[10,20])
操作形状

操作形状与numpy不一样,numpy可以直接调用,tensor不能,需要tf.reshape()

tf_const = tf.random.normal(shape=[10,20])

## 展开为1维向量
tf_const = tf.reshape(tf_const, -1)

tensorflow 采取 行优先 内存访问顺序,一般来说,tf.reshape 唯一合理的用途是合并或者拆分相邻轴

进行轴变换需要用到tf.transpose()

tf_const = tf.random.normal(shape=[10,20,30])

## 使原来的0,1,2 变成 1,2,0
tf.transpose(tf_const, [1,2,0])
数据提取和保存

张量切片与NumPy切片一样,也是基于索引。切片或者索引是Python语言中针对字符串、元祖或者列表进行读写的魔法方法,在第1章介绍NumPy的时候也提到过,针对NumPy数组,我们也可以进行索引或者切片操作。同样的,我们也可以对TensorFlow里面的张量进行索引或者切片操作,并且遵循Python语言或者说NumPy数组的索引规则。

  • 索引从下标0开始。
  • 负索引按照倒叙进行索引,比如 -1表示倒数第一个元素。
  • 切片的规则是start:stop:step。
  • 通过制定多个索引,可以对多维度张量进行索引或者切片。
变量

tensorflow 与 numpy 最不同的一点就是 tensorflow 有变量。

变量是深度学习在训练模型时用来存储和更新参数的,在创建的时候必须要初始化才能使用,即一定要赋值。变量和常量除了定义方式以外以及相关操作一致。

Numpy和Tensorflow的比较
操作类别NumPyTensorFlow 2+
数据类型np.ndarraytf.Tensor
np.float32tf.float32
np.float64tf.double
np.int64tf.int64
从已有数据构建np.array([3.2, 4.3], dtype=np.float16)a=tf.constant([3.2, 4.3], dtype=tf.float16)#常量 v=tf.Variable([3.2, 4.3], type=tf.float16)#变量
x.copy()tf.identity(x);tf.tile(a,(n,m))# 元组里的每个数值对应该轴复制次数
np.concatenatetf.concat((a,b),axis)# 待拼接的轴对应的维度数值可以不等,但其他维度形状需一致tf.stack((a,b),axis)# 带堆叠张量的所有维度数值必须相等
线性代数np.dot #内积 np.multiply(*)#逐元素相乘或哈达玛积tf.matmul(x, y, name=None) 或(@)#内积tf.multiply(x, y, name=None),或(*)#逐元素相乘或哈达玛积
属性x.ndimx.ndim
x.shapex.shape
x.sizetf.size(x)
改变形状x.reshapetf.reshape(x,(n,(-1)))#-1表示自动计算其他维度
np.transpose(x, [新的轴顺序] )tf.transpose(x, [新的轴顺序] )
x.flatten()tf.reshape(x,[-1]);tf.keras.layers.Flatten()
维度增减np.expand_dims(arr, axis)tf.expend_dims(a,axis)
np.squeeze(arr, axis)tf.squeeze(a,axis),#如果不声明axis,那么将压缩所有数值为1的维度。
类型转换np.floor(x)x=tf.cast(x,dtype=XX) x=x.numpy()=>np.array
比较np.lesstf.less(x,threshold)
np.less_equaltf.less_equal(x, threshold)
np.greater_equaltf.greater_equal(x, threshold)
随机种子np.random.seedtf.random.set_seed(n)

计算图

计算图类似于一个计算过程,具体可以看机器学习入门(10)— 浅显易懂的计算图、链式法则讲解_请画出该函数的计算图,请用方形节点表示-CSDN博客

Tensorflow目前有三种图:很拉跨的静态图,效率低的动态图以及方便的自动图。

TensorFlow有3种计算图:TensorFlow1.0时代的静态计算图,TensorFlow 2.0时代的动态计算图和Autograph。静态计算图,需要先使用TensorFlow的各种算子创建计算图,再开启一个会话(Session)执行计算图。 而在TensorFlow 2.0时代,默认采用的是动态计算图,即每使用一个算子后,该算子会被动态加入隐含的默认计算图中立即执行并获取返回结果,而无须执行Session。 使用动态计算图(即Eager Excution立即执行)的好处是方便调试程序,执行TensorFlow代码犹如执行Python代码一样,而且可以使用Python,非常便捷。不过使用动态计算图的坏处是运行效率相对会低一些,因为在执行动态图期间会有许多次Python进程和TensorFlow的C++进程之间的通信。而静态计算图不通过Python这个中间环节,基本在TensorFlow内核上使用C++代码执行,效率更高。 为了兼顾速度与性能,在TensorFlow 2.0中可以使用@tf.function装饰器将普通Python函数转换成对应的TensorFlow计算图构建代码。与执行静态图方式类似,使用@tf.function构建静态图的方式叫作Autograph(自动图)

静态图

其中静态图是1.0版本的产物,很拉,大概是这样子

import tensorflow as tf

#定义计算图
grap = tf.compat.v1.Graph()
with grap.as_default():
    #placeholder为占位符,执行会话时候指定填充对象
    x = tf.compat.v1.placeholder(tf.float32,shape=[],name='x')  
    y = tf.compat.v1.placeholder(tf.float32,shape=[],name='y')  
    b = tf.compat.v1.Variable(15.0,dtype=tf.float32) 
    z=tf.multiply(x,y,name='c')+b
    #初始化参数
    init_op = tf.compat.v1.global_variables_initializer()

#执行计算图
with tf.compat.v1.Session(graph = grap) as sess:
    sess.run(init_op)
    print(sess.run(fetches = z,feed_dict = {x:20,y:36}))

可以看到,先要创建Graph,然后要把计算写入Graph中,接着再进行计算。

动态图

以上代码如果采用动态计算图的方式实现,需要做如下处理。
1)把占位符改为其他张量,如tf.constant或tf.Variable。
2)无须显式创建计算图。
3)无须变量的初始化。
4)无须执行Session,把sess.run中的feed_dict改为传入函数的参数,fetches改为执行函数即可。
采用TensorFlow 2.0动态图执行的方式,代码如下:

import tensorflow as tf

#定义常量或变量
x=tf.constant(20,dtype=tf.float32)
y=tf.constant(36,dtype=tf.float32)

#定义函数
def mul(x,y):  
    #定义常量或变量
    b=tf.Variable(15 ,dtype=tf.float32) 
    z=tf.multiply(x,y,name='c')+b
    return z

#执行函数
print(mul(x,y).numpy())    

与静态计算图相比,可以看到动态计算图虽然调试编码效率高但是执行效率偏低

自动图

TensorFlow 2.0 之后的自动图(AutoGraph)可以将动态计算图转换成静态计算图,兼顾开发效率和执行效率。通过给函数添加@tf.function装饰器就可以实现AutoGraph功能,但是在编写函数时需要遵循一定的编码规范,否则可能达不到预期的效果,这些编码规范主要包括如下几点。

  • 避免在函数内部定义变量(tf.Variable)。
  • 函数体内应尽可能使用TensorFlow中的函数而不是Python语言自有函数。比如使用tf.print而不是print,使用tf.range而不是range,使用tf.constant(True)而不是True。
  • 函数体内不可修改该函数外部的Python列表或字典等数据结构变量。

用@tf.fuction装饰函数,把动态计算图转换为自动图如下:

import tensorflow as tf

#定义常量或变量
x=tf.constant(20,dtype=tf.float32)
y=tf.constant(36,dtype=tf.float32)
b=tf.Variable(15 ,dtype=tf.float32)
#定义函数
@tf.function
def mul(x,y):  
    # 定义常量或变量
    # b=tf.Variable(15 ,dtype=tf.float32) # 不可以在自动图里定义变量
    z=tf.multiply(x,y,name='c')+b
    return z

#执行函数
print(mul(x,y).numpy())     

这样看起来不爽,可以用类包装一下就好看了

import tensorflow as tf

#定义一个类
class Test_Mul:
    def __init__(self):
        super(Test_Mul, self).__init__()
        self.b=tf.Variable(15 ,dtype=tf.float32) 

    @tf.function
    def mul(self,x,y):      
        z=tf.multiply(x,y,name='c')+self.b
        return z

#执行函数
x=tf.constant(20,dtype=tf.float32)
y=tf.constant(36,dtype=tf.float32)
Test=Test_Mul()
print(Test.mul(x,y).numpy())     

自动微分

构建计算图后,肯定是需要计算微分求导数的,tensorflow深度学习架构帮助我们自动地完成了求梯度运算。 Tensorflow一般使用梯度磁带tf.GradientTape来记录正向运算过程,然后使用反播磁带自动得到梯度值。

![[Pasted image 20240506152908.png]]

按照上述流程进行一次微分

import tensorflow as tf
import numpy as np 

# f(x) = a*x**2 + b*x + c的导数
#缺省情况,张量tf.constant为常量,只有变量tf.Variable作为参数更新
x = tf.Variable(0.0,name = "x",dtype = tf.float32)
a = tf.constant(1.0)
b = tf.constant(5.0)
c = tf.constant(2.0)

with tf.GradientTape() as tape:
    tape.watch([a,b,c]) # 这里abc是张量,如果不需要观察张量的导数,可以删掉
    y = a*tf.pow(x,2) + b*x + c
    
dy_dx,dy_da,_,dy_dc = tape.gradient(y,[x,a,b,c])
print(dy_da)
print(dy_dc)

二次微分可以使用嵌套的方式:

with tf.GradientTape() as tape2:
    with tf.GradientTape() as tape1:   
        y = a*tf.pow(x,2) + b*x + c
    dy_dx = tape1.gradient(y,x)   
dy2_dx2 = tape2.gradient(dy_dx,x)

print(dy2_dx2)

这里要注意的是:梯度磁带会自动监视 tf.Variable,但不会监视 tf.Tensor。如果无意中将变量(tf.Variable)变为常量(tf.Tensor)(如tf.Variable 与一个tf.Tensor相加,其和就变成常量了),梯度磁带将不再监控tf.Tensor。 为避免这种情况,可使用 Variable.assign 给tf.Variable赋值

x = tf.Variable(2.0)

for epoch in range(2):
  with tf.GradientTape() as tape:
    y = x+1

  dy_x=tape.gradient(y, x)
  #print(type(x).__name__, ":", tape.gradient(y, x))
  print(dy_x)
  #变量变为常量tf.Tensor
  x = x + 1   # This should be `x.assign_add(1)`

最后要记得删除tape!!!

del tape

使用Tensorflow 实现回归

上一节numpy一样,设置一样的函数如下:

y = 3 x 2 + 2 x + 1 y=3x^2+2x+1 y=3x2+2x+1

图像如下:
![[Pasted image 20240505194741.png]]

假设知道最高项为3,设函数为: y = a x 2 + b x + c y=ax^2+bx+c y=ax2+bx+c

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

## 准备数据
np.random.seed(42)  
  
x = np.linspace(-10, 10, 50)  
y = 3 * np.power(x, 2) + 2 * x + 1

a = np.random.random(size=(1, 1))  
b = np.random.random(size=(1, 1))  
c = np.random.random(size=(1, 1))  

## 定义模型
class LinearRegression:
    def __init__(self):
        self.a = tf.Variable(a)
        self.b = tf.Variable(b)
        self.c = tf.Variable(c)

    def __call__(self, x):
        return self.a * tf.square(x) + self.b * x + self.c

model = LinearRegression()

## 定义损失
@tf.function
def compute_loss(y, y_pred):
    return tf.reduce_mean(tf.square(y-y_pred))

## 定义训练过程
def train_one_epoch(x, y, lr=1e-4):
    with tf.GradientTape() as tape:
        y_pred = model(x)
        loss = compute_loss(y, y_pred)
    a, b, c = model.a, model.b, model.c
    da, db, dc = tape.gradient(loss, [a, b, c])
    a.assign(a - lr*da)
    b.assign(b - lr*db)
    c.assign(c - lr*dc)
    return loss.numpy()


## 计算loss
loss_list = []
for i in range(30):
    loss = train_one_epoch(x, y)
    loss_list.append(loss)


## 画出loss图
plt.plot(loss_list)

得到的损失变化如下:

![[Pasted image 20240506161250.png]]

这里学习率过高会导致不收敛,出现loss反而变大的情况,同时学习率过低可以会导致loss下降得很慢,因此这里可以使用官方定义的优化器来进行梯度更新,这会减少assign代码。

## 定义训练过程
def train_one_epoch(x, y, lr=1e-4):
    with tf.GradientTape() as tape:
        y_pred = model(x)
        loss = compute_loss(y, y_pred)
    a, b, c = model.a, model.b, model.c
    da, db, dc = tape.gradient(loss, [a, b, c])
    a.assign(a - lr*da)
    b.assign(b - lr*db)
    c.assign(c - lr*dc)
    return loss.numpy()

# 替换成

## 定义优化器
opt = tf.keras.optimizers.Adam(learning_rate=1e-1)

## 定义训练过程
def train_one_epoch(x, y):
    with tf.GradientTape() as tape:
        y_pred = model(x)
        loss = compute_loss(y, y_pred)
    a, b, c = model.a, model.b, model.c
    da, db, dc = tape.gradient(loss, [a, b, c])
    opt.apply_gradients(grads_and_vars=zip([da,db,dc], [a,b,c]))
    return loss.numpy()

如果要使用minimize这种更为简单的形式,这里我们需要把loss计算整合一下:

@tf.function
def get_loss():
    y_pred = model(x)
    loss = compute_loss(y, y_pred)
    return loss


## 定义训练过程
def train_one_epoch(x, y):
    a, b, c = model.a, model.b, model.c
    opt.minimize(get_loss, [a, b, c])
    return get_loss()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1669896.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

iOS 面试题总结(可能是最全的!!!)

如有错误 请及时在评论中指出 文章将不定期更新 1. objc_msgForward是干什么的,如果直接调用会发生什么? 作用:这个函数是IMP类型(方法实现的内存地址也就是函数指针),用于消息转发,当向一个对…

【Linux】多线程相关第一篇:从进程谈起理解线程概念

文章目录 为什么需要线程初步认识Linux线程Linux操作系统的线程为什么要这么设计进程、线程关系梳理理解线程是CPU调度的基本单位简单认识多执行流如何划分代码 为什么需要线程 线程和进程的关系密不可分。 操作系统教材对于进程、线程的概念是这样描述的: 进程是…

Python-VBA函数之旅-super函数

目录 一、super函数的常见应用场景 二、super函数使用注意事项 三、如何用好super函数? 1、super函数: 1-1、Python: 1-2、VBA: 2、推荐阅读: 个人主页: https://myelsa1024.blog.csdn.net/ 一、su…

JS解密之新js加密实战(二)

前言 上次发了一篇关于新加密的,只解了前边两层,这中间家里各种事情因素影响,没有继续进一步研究,今天百忙之中抽空发布第二篇,关于其中的一小段加密片段,我认为分割成多个小片段是更容易被理解的。逻辑相…

【SRC实战】修改赠送金额支付漏洞

挖个洞先 https://mp.weixin.qq.com/s/NQKJQF81XpG8815EfgvgKw “ 以下漏洞均为实验靶场,如有雷同,纯属巧合 ” 01 — 漏洞证明 “ 充值赠送金额能否修改? ” 1、充值30元赠送1.9元礼包,充值100元赠送7元礼包,充值…

买卖股票的最佳时机 II(LeetCode 122)

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…

FANUC机器人单轴零点标定时提示无法执行零点标定,由于重力补偿已启用,所有机器人轴的脉冲计数必须有效

FANUC机器人单轴零点标定时提示无法执行零点标定,由于重力补偿已启用,所有机器人轴的脉冲计数必须有效 首先,机器人由于长时间断电未使用,6个轴的编码器数据全部丢失,上电后报警SRVO-062, 有关SRVO-062故障报警的相关内容可参考以下链接: FANUC机器人SRVO-062报警原因分…

通过集成式 PLM Services for SIMULIA 实现协作

在快速发展的产品开发世界中,无缝和高效的管理解决方案已成为必需品。在这些解决方案中,PLM 服务正变得越来越普及,这要归功于它们的能力。这些服务提供了一种管理产品生命周期的集成方法,从概念开始,到设计和制造&…

Pyhton专题学习资料包,Python从入门到精通全套学习资料[30G]

资源概览 百本Python学习书籍大礼包百本前端学习书籍大礼包微专业-数据挖掘分析之Python篇小甲鱼零基础入门学习Python(全96集) 资源获取 🧑‍💻【Pyhton专题资料】【30G】 百本Python书籍## 百本前端书籍 微专业-数据挖掘分析之Python篇 预备课【先…

Docker下Open WebUI,Ollama的安装实践

提示一下Open WebUI与ollama的关系。后端的同学可以理解为Open WebUI等于是个Navicat,Ollama就是具体的数据库实例。 官方安装文档: 🏡 Home | Open WebUI Open WebUI官网文档翻译: 注意: 使用Docker安装Open WebU…

有趣的css - 打字机动画效果

大家好,我是 Just,这里是「设计师工作日常」,今天分享的是使用 css 实现好玩的单行打字机效果,和我一起看看吧。 《有趣的css》系列最新实例通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html 代码css 部分代码 完整…

成员函数构造函数析构函数

文章目录 类的6个默认成员函数构造函数概述定义特性 析构函数概述特性 类的6个默认成员函数 空类: 如果一个类里面什么都没有写,我们称之为空类 class Date {};空类真的什么都没有吗? 实际上并非如此,编译器会自动生成6个默认成…

樊春海院士/姚广保课题组2024年博士后/助理研究员火热招募!

尊敬的读者们,我们很高兴地向您介绍一个激动人心的机会——上海交通大学张江高等研究院正在进行博士后和科研助理的招聘,这是一个与顶尖科学家共事、参与前沿科学研究的绝佳机会。 工作地点位于风景优美、充满活力的上海市浦东新区,这里是中国…

FENDI CLUB精酿啤酒馆与传统啤酒销售模式的不同

精酿啤酒火了,国产品牌精酿也在迅速崛起,为精酿啤酒这一小众品类发展加足了马力。与此同时,精酿酒吧、精酿小酒馆也开始出现了增长。这标志着中国精酿啤酒市场的快速发展和国产品牌的崭新局面。 FENDI CLUB精酿啤酒已经在不少地方开始积极开…

CDGA|数据治理实战案例:从数据收集到治理,再到价值应用

在当今信息爆炸的时代,数据治理已成为企业提升核心竞争力、实现数字化转型的关键一环。本文将通过一个实战案例,详细剖析数据治理的全过程,从数据收集到治理,再到价值应用,为读者提供有益的参考和启示。 数据收集&…

港中深「户外自重构蜗牛机器人集群」登Nature子刊!

在科幻电影《超能陆战队》中,我们见证了一种由成千上万个微小磁性单元组成的机器人通过磁力相互连接,形成各种复杂的三维结构。香港中文大学(深圳)林天麟教授团队致力于将这一科幻转化为现实,近年来开发了一系列自由形…

APP反抓包 - 客户端证书验证

一,校验的原理 下图为HTTP协议的请求过程:传输过程中都是明文数据 下图为HTTPS协议的请求过程: 注意:公钥加密的数据只能通过对应的私钥才能解密,就算是进行加密的公钥也不能进行解密。 上述的请求过程看似复杂,实际就是两部分: 通过公钥与私钥同步对称密钥使用对…

安科瑞工业IT产品及解决方案—电源不接地,设备外壳接地【监测系统对地绝缘电阻】

低压配电系统分类及接地保护方案 国际电工委员会(iec)对各接地方式供电系统的规定规定:(低压:交流1000V以下) 低压配电接地、接零系统分为IT、TT、TN三种基本形式。TN分为TN-C,TN-S,TN-C-S三种…

网络编程UDP

目录 1.什么是网络编程 1.1发送端和接收端 1.2请求和响应 1.3客户端和服务端 1.4常见的客户端服务端模型 2.Socket套接字 2.1Socket概念 2.2三种Socket套接字分类 3.Java数据报套接字通信模型(UDP) 4.Socket编程注意事项 5.UDP数据报套接字编程…

只需三步,教你轻松搞定内网穿透

最近开发过程中又遇到了需要外网访问内部服务接口的需求,比如调用三方服务的各种回调通知、支付成功回调、大模型回调等都需要外部服务器来访问内部的接口,这里有个问题就是如果我们在本地或者测试环境调试的过程中我们使用的是内网环境,那外…