分类 编程语言 下的文章

基本的数值计算相关操作

摘自 https://blog.csdn.net/zywvvd/article/details/78593618 一般前提条件为参与运算的数据类型相同。这些操作可以直接在tensorflow.Session中执行。

    # 常量的定义
    # 其中若data为浮点数,而不显式声明dtype的话,dtype将被隐式地设定为tf.float32
    tf.constant(data, dtype)

    # 变量类型转换
    tf.cast(data, dtype)

    # 算术操作符:+ - * / % 
    tf.add(x, y, name=None)        # 加法(支持广播)
    tf.subtract(x, y, name=None)   # 减法
    tf.multiply(x, y, name=None)   # 元素级乘法 -> 矩阵乘法为tf.matmul()
    tf.divide(x, y, name=None)     # 浮点除法, 返回浮点数
    tf.mod(x, y, name=None)        # 取余

    # 幂指对数操作符:^ ^2 ^0.5 e^ ln 
    tf.pow(x, y, name=None)        # 幂次方
    tf.square(x, name=None)        # 平方
    tf.sqrt(x, name=None)          # 开根号,必须传入浮点数或复数
    tf.exp(x, name=None)           # 计算 e 的次方
    tf.log(x, name=None)           # 以 e 为底,必须传入浮点数或复数

    # 取符号、负、倒数、绝对值、近似、两数中较大/小的
    tf.negative(x, name=None)      # 取负(y = -x)
    tf.sign(x, name=None)          # 返回 x 的符号
    tf.reciprocal(x, name=None)    # 取倒数
    tf.abs(x, name=None)           # 求绝对值
    tf.round(x, name=None)         # 四舍五入
    tf.ceil(x, name=None)          # 向上取整
    tf.floor(x, name=None)         # 向下取整
    tf.rint(x, name=None)          # 取最接近的整数 
    tf.maximum(x, y, name=None)    # 返回两tensor中的最大值 (x > y ? x : y)
    tf.minimum(x, y, name=None)    # 返回两tensor中的最小值 (x < y ? x : y)

    # 三角函数和反三角函数
    tf.cos(x, name=None)    
    tf.sin(x, name=None)    
    tf.tan(x, name=None)    
    tf.acos(x, name=None)
    tf.asin(x, name=None)
    tf.atan(x, name=None)   

    # 其它
    tf.div(x, y, name=None)  # python 2.7 除法, x/y-->int or x/float(y)-->float
    tf.truediv(x, y, name=None) # python 3 除法, x/y-->float
    tf.floordiv(x, y, name=None)  # python 3 除法, x//y-->int
    tf.realdiv(x, y, name=None)
    tf.truncatediv(x, y, name=None)
    tf.floor_div(x, y, name=None)
    tf.truncatemod(x, y, name=None)
    tf.floormod(x, y, name=None)
    tf.cross(x, y, name=None)
    tf.add_n(inputs, name=None)  # inputs: A list of Tensor objects, each with same shape and type
    tf.squared_difference(x, y, name=None) 

需要注意的一点是,由于TensorFlow的编程模型为流图模式,实际上在运行过程中每个张量都只会被计算一次,因而每次定义新Tensor的时候,只是会把旧Tensor的引用去除,旧Tensor的操作还是会在流图中运行。因而,若是定义了一个语法错误的Tensor的话就麻烦了,会直接报错。。。(惨痛的教训)
20190724 目前还没发现Python可以从流图中删除Tensor的方法,StackOverflow和GitHub上都说没有可行的办法,“没有办法干净利落地从流图中删除一个结点”。因而只有另一个方法:在必要情况下换用新图。使用tf.reset_default_graph()也没有用,根据实测,它只会“清空”默认图,可以定义新变量,但是只能运行旧的流图。也就是说实际上鸟用没有

变量与作用域

改编自https://www.jianshu.com/p/2061b221cd8f , https://www.cnblogs.com/esCharacter/p/7872064.html 根据定义,tensorflow.Variable可以用于定义一个变量。变量之间的运算被定义为Tensor,中文名称为张量,是物理学中一种不随坐标系改变而发生变化的物理量,在TensorFlow中为运算操作的表达方式。(然而由于在下数学能力实在缺乏,只能Python编程中近似将其理解为多维矩阵)使用Variable类的构造函数进行变量定义要求非空的初始化值。对应有一个方法可以达到相似的目的:tensorflow.get_variable()。两者的联系与区别如下:

  tensorflow.Variable() tensorflow.get_variable()
命名重复 新变量自动重命名 报错
对象引用 每次调用创建新对象 在同一作用域下可以引用同名对象

根据作者描述,在通过tensorflow.variable_scope()定义作用域后,可以通过tensorflow.get_variable()进行变量的重用。其意义在于,可以通过作用域的临时定义(with tf.Graph().as_default():)进行上下文的切换,提供了便捷的变量存取方法。

tensorflow.Variable(tensorflow.Tensor)语句只会构建计算图。这些tensorflow.Tensor对象仅代表将要运行的操作的结果,是一种流图语言的定义语句,因而并不可以直接输出,需要在tensorflow.Session里运行后获得结果。返回值为numpy.ndarray格式。 部分代码如下:

a = tf.Variable([[1,2],[3,4]], name='a')
sess.run(a)

完整执行过程将于下一节 [tensorflow“执行器” session] 中讲述。

tensorflow“执行器” Session

根据字面意义上理解,session可以理解为会话,也就是说相当于启动了一个“执行器”。以我初学者的个人简介来看,就像是一套净化水装置的入口开关开启,接下来就可以装入数据进行处理了。上一节 [变量与作用域] 中的sess就是这里的tensorflow.Session。sess的创建方式很简单:

import tensorflow as tf

sess = tf.Session()

但是若是在创建完Session之后将上一节的代码复制粘贴入运行,会出现这么一个问题:

tensorflow.python.framework.errors_impl.FailedPreconditionError: Attempting to use uninitialized value Variable

根据字面意思,显然是变量未初始化。若是需要使用tensorflow.Variable一类的对象变量的话,需要先在Session中进行初始化:

sess.run(tf.global_variables_initializer())

然后可以获得结果:

>>> sess.run(a)
array([[1, 2],
       [3, 4]])

可以使用sess.close()手动关闭Session。虽然GPU指示器显示Python仍然在占用cpu,但是重新建立会话

摘自官方文档:

可以将多个张量传递给tf.Session.runrun方法以透明方式处理元组或字典的任何组合,如下例所示:

print(sess.run({'ab':(a, b), 'total':total}))

它返回的结果拥有相同的布局结构:

{'total': 7.0, 'ab': (3.0, 4.0)}

因为字典没有排序规则,所以实际上对于使用影响不大。

限制运行时GPU内存占用的方法:

import tensorflow as tf
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.3
sess = tf.Session(config=config)

通过设置per_process_gpu_memory_fraction来限制GPU内存的使用比例。

根据个人理解,其本质上是对于某些特殊的、形状不相符的数组进行一定规则的变化,使得数组间满足矩阵运算的规则。(说不定也可以理解为是简化输入的一种方式?)

首先说一句,似乎现在网上很多博客都喜欢把多维数组的维度单独称为轴。。。 为啥不干脆叫多轴数组算了

根据https://www.cnblogs.com/yangmang/p/7125458.html的介绍,广播的发生条件可以用如下方法判断: 将两个多维数组的维度数组后端对齐,依次从后往前比较,若是都满足以下条件则可以进行广播:

  1. 维度的大小(轴长)相等;
  2. 其中一个多维数组的维度大小为1(至少其中一个多维数组在该维度的轴长为1);
  3. 其中一个多维数组不存在该维度。

举例如下:

shape(5, 4, 3, 2, 1)
shape(   4, 2, 1, 1)

按照从右往左进行计数的话,有: 第一维满足条件1、2; 第二维满足条件2; 第三维不满足任何条件; 第四维满足条件1; 第五维满足条件3。 因而,由于第三维不满足任何条件,这两个多维数组间在运算时不能发生广播;但若去除第三维,可以由第二个数组进行广播,使用尾部剩余维度的数据填充,直至与第一个数组形状相同,然后进行元素级别的运算。

数组 [[[[1,2], [3,4]],

[[1,2], [3,4]]],

[[[1,2], [3,4]],

[[1,2], [3,4]]],

[[[1,2], [3,4]],

[[1,2], [3,4]]],

[[[1,2], [3,4]],

[[1,2], [3,4]]]] 可以与数组 [[[1],[2]]] 进行相加操作,结果为上面数组中的[[1,2],[3,4]]单元全部变为[[2,3],[5,6]]。 有没有两个多维数组间的相互传播有待测试。

  1. numpy定义和使用的矩阵类型为numpy.ndarray

  2. 正态分布的随机数多维数组
numpy.random.rand()

用于生成一组[0,1)范围内的随机数。根据函数定义描述,生成的随数值符合正态分布。 可以向该函数传递n(n>=1)个整型参数,返回格式为一个大小与传递参数值相同的n维矩阵。

  1. 矩阵乘法
<ndarray> * <ndarray>        # 元素级乘法
numpy.dot(mat1, mat2)        # 矩阵点乘
numpy.cross(mat1, mat2)      # 矩阵叉乘
numpy.tensordot(mat1, mat2)  # 张量乘法?

四种乘法,传入两个ndarray,返回他们的相应操作结果。 若是不符合相应的规则,将会报出ValueError错误。

  1. 矩阵区域赋值

左侧使用:[]运算符限定好范围,右侧放待赋值的矩阵,用等号连接即可。

Gradle是一个基于Apache Ant和Apache Maven概念的项目自动化构建开源工具... ...当前其支持的语言限于Java、Groovy、Kotlin和Scala...

嗯,没错,这就是我把它归类到 编程语言/Java 而不是 软件/编译 的原因。

相比于maven,Eclipse对于gradle的可视化操作的友好程度大大下降。只提供最基础的项目创建、任务运行(修改了配置文件之后居然还不会自动更新任务)和配置文件高亮功能。甚至连依赖配置都只能自己动手修改文件完成。虽然不难,但是不直观啊,对新手入门也不友好。反正我是搜了好久教程,七拼八凑弄出来的。

简要列出三大运行项目的方法[1]

  1. 暴力寻找主类运行。由于gradle只是一个项目构建工具(和cmake有点像?),并不负责对被处理对象进行运行操作,故默认状态下我们只能得到编译好的class文件。故最原始粗暴的方法便是手动为Eclipse指定一个运行时的主类。而当Eclipse在检测到所有项目文件均已编译好时,会直接运行项目,间接达到了目的:因为依赖配置使用的是gradle,直接使用Eclipse调用javac编译的话可能会出现缺少包的错误。

  2. 加载application插件。gradle可以通过插件扩展其功能。application插件能够为gradle添加一个Application Tasks/run的任务,通过该任务可以直接运行项目。 在build.gradle文件的最外层里添加

    apply plugin 'application'
    mainClassName = 'your.main.class'

    your.main.class换成项目的入口类,会自动调用其main方法运行项目。 没有mainClassName的话,buildrun任务都会出错,因为application插件将不知道你需要将哪个包作为应用程序运行。

  3. 这个更暴力了。。编译成jar然后自己去命令行运行(捂脸)
    jar {
    manifest.attributes 'Main-Class': 'com.mycompany.Main'
    from configuration.compile.collect { zipTree it}
    }

    然后gradle/gradlew build生成jar包,然后用对应的java命令执行(通常是java -jar file.jar)即可。

添加依赖的方法:

  1. 最简单粗暴(对应maven):

    <scope> '<group>:<artifact>:<version>'
    =======================================================
    <scope> IN compile, test, testCompile, runtime, etc.

    scope与maven中的部分对应。 例:runtime 'mysql:mysql-connector-java' << 最后一个版本号可以省略,应该是默认取最新版本吧?

  2. 优雅一点:

    <scope> group: '...', name: '...', version: '...'
    =======================================================
    <scope> IN compile, test, testCompile, runtime, etc.

    例:runtime group: 'mysql', name: 'mysql-connector-java', version: '8.0.16'

  3. 本地文件:
    <scope> fileTree(dir: 'lib', includes: ['mysql-connector-java-8.0.16.jar'])
    =======================================================
    <scope> IN compile, test, testCompile, runtime, etc.

    该写法会让gradle到项目根目录下的lib文件夹里寻找mysql-connector-java-8.0.16.jar

参考: [1] https://www.cnblogs.com/yongheng20/p/6161160.html

在写项目的时候,先写了个爬虫,用了官方的json库,写完运行,没问题。 之后打算把爬虫的信息处理之后用REST写成api,然后就选择了Springboot。 把项目内的源代码原封不动地复制过去,然后,报错了???

之后还是在神奇的stackoverflow上找到了原因:在spring-boot-starter-test组件里,调用了非官方的android-json库。 https://stackoverflow.com/questions/52980064/maven-spring-boot-found-multiple-occurrences-of-org-json-jsonobject-on-the-cl

而这两者之间的差距在于,我所使用的官方库在解析错误时报出的是非检查性异常RuntimeException,也就是不影响代码语法的错误,运行时碰到就直接输出报错信息,停止这一过程了。而android-json库报出的是检查性异常Exception,用户必须在编写代码时就考虑该问题的解决,即try-catch

解决方案在上文链接里也有提到,在pom.xml里把该组建排除依赖即可。在eclipse里可通过图形界面简单操作。

最后再来小声bb一段:怎么又是咕果家的东西……

真的是只有商业公司才上心吗,firefox又给自己搞事情……

不想用chrome啊……