运筹系列43:julia用于科学计算

如果出现git问题,切换shell模式,执行:
git config --global http.proxy ‘socks5://127.0.0.1:1080’
git config --global https.proxy ‘socks5://127.0.0.1:1080’

1. 基础

1.1 Dataframe

# 新建一个DataFrame并增加4列内容

using DataFrames
df1 = DataFrame()
df1[:clo1] = Array([1.0,2.0,3.0])
df1[:clo2] = Array([4.0,5.0,6.0])
df1[:clo3] = Array([7.0,8.0,9.0])
df1[:ID] = Array(['a','b','c'])
show(df1)
>>3×4 DataFrame
│ Row │ clo1    │ clo2    │ clo3    │ ID   │
│     │ Float64 │ Float64 │ Float64 │ Char │
├─────┼─────────┼─────────┼─────────┼──────┤
│ 1   │ 1.0     │ 4.0     │ 7.0     │ 'a'  │
│ 2   │ 2.0     │ 5.0     │ 8.0     │ 'b'  │
│ 3   │ 3.0     │ 6.0     │ 9.0     │ 'c'  │

# 如果没有指定列名,则默认是x1,x2...

df2 = DataFrame(rand(5,6))
# 在DataFrame定义时直接指定内容

df3 = DataFrame([collect(1:3),collect(4:6)], [:A, :B])
>>    A   B
  Int64    Int64
1    1   4
2    2   5
3    3   6

运筹系列43:julia用于科学计算_第1张图片
运筹系列43:julia用于科学计算_第2张图片
运筹系列43:julia用于科学计算_第3张图片
运筹系列43:julia用于科学计算_第4张图片
运筹系列43:julia用于科学计算_第5张图片
运筹系列43:julia用于科学计算_第6张图片
RDatasets是Julia中的一个数据集,里面包含了很多可以学习和验证的数据,其中就包括iris数据集。
运筹系列43:julia用于科学计算_第7张图片
下面是直接读取csv、xlxs、txt文件的方法
运筹系列43:julia用于科学计算_第8张图片

运筹系列43:julia用于科学计算_第9张图片
运筹系列43:julia用于科学计算_第10张图片
下面是一些基础操作:
运筹系列43:julia用于科学计算_第11张图片
运筹系列43:julia用于科学计算_第12张图片
运筹系列43:julia用于科学计算_第13张图片
运筹系列43:julia用于科学计算_第14张图片
运筹系列43:julia用于科学计算_第15张图片
运筹系列43:julia用于科学计算_第16张图片
运筹系列43:julia用于科学计算_第17张图片
注意最后三者的差别。
下面是修改数据的方法:
运筹系列43:julia用于科学计算_第18张图片

1.2 时间序列

运筹系列43:julia用于科学计算_第19张图片
运筹系列43:julia用于科学计算_第20张图片

1.3 机器学习等

机器学习库自己可以搜
深度学习库是Flux

1.4 加速性能

首先要关注一下特殊符号,例如eltype函数:

function eltype(::Type{<:AbstractDict{K,V}}) where {K,V}
    if @isdefined(K)
        if @isdefined(V)
            return Pair{K,V}
        else
            return Pair{K}
        end
    elseif @isdefined(V)
        return Pair{k,V} where k
    else
        return Pair
    end
end

其中:
1.{}用来表示类型的参数化(泛型),比如说Vector{Int}表示一个整数的向量,在Java(以及C++)中用<>表示,例如List
2.[]表示数组
3.()可以表示元组(和Haskell,Python一致),如(1,2,3),也可以表示函数调用,如sum([1,2,3])
3.A<:B表示类型子类化(A是B的子类,a::B表示a的类型是B)
4.where引导类型变量,例如Array{T,3} where T表示一个3维数组,数组元素的类型为某个待定的T,可以提高性能
5.一个点 . ,如A.a,表示A有个属性为a;. 还可以用来表示broadcast,可以理解为就是map,例如说,你有一个矩阵A,sin.(A)表示将A中元素分别求正弦后得到的新矩阵,等价于map(sin,A)
6.@表示宏调用(Julia本来也可以不用@标记宏,但是为了大家方便阅读,最后还是强制要求用@标记)
7.Julia中有生成函数(一种特殊函数),本质上是一个返回表达式的函数,然后表达式会插入函数所在处执行了。这个东西创造出来是为了利用LLVM的多层次编译优势(运行时动态生成优化代码),主要用于优化(而且被大量使用)例如在文档中的例子:

julia> @generated function bar(x)
           if x <: Integer
               return :(x ^ 2)
           else
               return :(x)
           end
       end
bar (generic function with 1 method)
 
julia> bar(4)
16
 
julia> bar("baz")
"baz"
  1. 在Julia中,值只有具体类型,不可能有抽象类型,只有抽象类型能被子类化,具体类型不可以,具体说来,就是上述类型树中,只有叶子节点才能被构造出来,其他的节点是不可构造的。这是很有趣的一个地方,这表明,Julia的tag系统全都是具体类型组成的,那抽象类型有什么用呢?抽象类型用来确定子类化关系,以做多重派发以实现ad hoc多态(并且只有这个用处)

避免全局变量,把全局变量声明为常量可以巨大的提升性能。如果必须要声明全局变量,可以在使用它的地方标注他们的类型来优化效率。
任何注重性能或者需要测试性能的代码都应该被放置在函数之中。
可以通过@code来查看用于code generation的宏
下面是测试例子:

global x = rand(10000)

function lp1() # 直接动用全局变量
    s = 0.0
    for i in x
        s += i
    end
end

function lp2() # 指定全局变量类型
    s = 0.0
    for i in x::Vector{Float64}
        s += i
    end
end

function lp3(x) # 将变量以参数形式传入
    s = 0.0
    for i in x
        s += i
    end
end

运筹系列43:julia用于科学计算_第21张图片
指定类型是速度最快的,原理如下:
当我们定义一个函数时,如果函数参数的类型是固定的,比如是一个Int64的Array[1,2,3,4],那他们在内存中会连续存放;
但如果函数参数的类型是Any,那么内存中连续存放只是他们的“指针”,会指向其实际的位置。这样一来,数据存取就慢下来了。计算concrete类型会比计算abstract类型要节省时间,我们可以使用@code_warntype来查看运行的函数中是否有abstract类型,对于有abstract类型的地方,会用红色的标出。
运筹系列43:julia用于科学计算_第22张图片
可以用如下函数来获得相同的数据类型:
zero(value)
eltype(array)
one(value)
similar(array)
向量化并不会提高Julia的运行速度,@simd 可以在运算支持被重新recorded时加速运算
输出预分配可以提高性能
避免不必要的Array,比如计算x,y,z的和时,使用x+y+z,不要用sum([x,y,z])
用div(x,y)代替trunc(x/y),用fld(x,y)代替floor(x/y),用cld(x,y)代替ceil(x/y),有现成的函数就不要自己写计算过程

2. GPU使用

2.1 安装与测试

pkg> add CUDA
pkg> test CUDA

先测试一下CPU的串行和并行版本:
运筹系列43:julia用于科学计算_第23张图片

下面是cuda版本

使用GPU简单到令人感动,pkg中add CUDAdrv即可:

julia> using CUDAdrv
julia> CUDAdrv.name(CuDevice(0))
"Tesla P4"

关于GPU的一些注意事项:

GPU是一个独立的硬件,具有自己的内存空间和不同的架构。 因此,从RAM到GPU存储器(VRAM)的传输时间很长。 即使在GPU上启动内核(换句话说,调度函数调用)也会带来较大的延迟。 GPU的时间约为10us,而CPU的时间则为几纳秒。
较低的精度是默认值,而较高的精度计算可以轻松地消除所有性能增益
GPU函数(内核)本质上是并行的,所以编写GPU内核至少和编写并行CPU代码一样困难,因此许多算法都不能很好地移植到GPU上。内核通常是用C/ C++编写的,这并不是写算法的最佳语言。
CUDA和OpenCL之间存在分歧,OpenCL是用于编写低级GPU代码的主要框架。虽然CUDA只支持英伟达硬件,但OpenCL支持所有硬件,但有些粗糙。

你可能感兴趣的:(运筹学,算法)