View in NBViewer Open in binder Download notebook View source


4.6. Redes neurais

\[ x \mapsto g(Wx + b), \]

onde \(g : \mathbb{R} \rightarrow \mathbb{R}\) é chamada de função de ativação, \(W\) é uma matriz de pesos e \(b\), de viés.

using LinearAlgebra: ⋅
using Flux
using Plots
using ChainPlots

Perceptron com dois sinais de entrada

\[ \text{saída} = \begin{cases} 0, & \displaystyle \text{se } w_1x_1 + w_2x_2 \leq r, \\ 1, & \displaystyle \text{se } w_1x_1 + w_2x_2 > r. \end{cases} \]

Perceptrons com múltiplos sinais de entrada

\[ \text{saída} = \begin{cases} 0, & \displaystyle \text{se } \sum_{i=1}^n w_ix_i + b \leq 0, \\ 1, & \displaystyle \text{se } \sum_{i=1}^n w_ix_i + b > 0. \end{cases} \] \[ h(s) = \max\{0,\operatorname{sgn}(x)\} = \begin{cases} 1, & s>0 \\ 0, & s\leq 0 \end{cases} \] \[ W = \left[w_1 w_2 \ldots w_n\right] \in \mathbb{R}^{1 \times n}. \] \[ \text{saída} = h\left(w_1x_1 + \ldots + w_nx_n + b\right) = h\left(Wx + b\right). \]

Implementando um perceptron em Julia

n = 2                      # número de entradas
W = [0.6 0.8]              # pesos
b = 1.0                    # viés
h(s) = ifelse(s > 0.0, 1.0, 0.0)   # função de ativação

l(x, h, W, b) = h.(W * x .+ b)         # perceptron
l (generic function with 1 method)
l(2, h, 0.6, 1)
1.0
l([1, 2], h, [0.6 0.2], [2, 2])
2-element Vector{Float64}:
 1.0
 1.0
l([1 2; 3 4], h, [-1 1], [1; 2])
2×2 Matrix{Float64}:
 1.0  1.0
 1.0  1.0
plot(-2:0.001:2, h, legend=false,
    title="Gráfico da função de ativação s ↦ ifelse(s>0, 1, 0)", titlefont=11)
surface(-5:0.1:5, -5:0.1:5, (x,y) -> l([x,y], h, W, b)[1], c=:bluesreds,
    title="Gráfico do sinal de saída de um perceptron com duas entradas",
    titlefont=11)

Redes de perceptrons.

Outras funções de ativação

NNlib.ACTIVATIONS
24-element Vector{Symbol}:
 :σ
 :hardσ
 :hardtanh
 :relu
 :leakyrelu
 :relu6
 :rrelu
 :elu
 :gelu
 :swish
 ⋮
 :logσ
 :logcosh
 :mish
 :tanhshrink
 :softshrink
 :trelu
 :lisht
 :tanh_fast
 :sigmoid_fast
\[ σ(x) = \frac{1}{1 + \exp(-x)}. \]
plot(-10:0.1:10, NNlib.σ, legend=false,
    title="Gráfico da sigmoid `σ(x) = 1 / (1 + exp(-x))`", titlefont=11)

Visualizando todas as funções de ativação

ativacoes = hcat([getproperty(NNlib, ativacao).(-10:0.1:10) for ativacao in NNlib.ACTIVATIONS[1:end]]...)
nothing
ncols = 3
nlinhas = divrem(length(NNlib.ACTIVATIONS), ncols) |> drn -> drn[1] + sign(drn[2])
plot(ativacoes, layout = grid(nlinhas, ncols), legend=false, size=(600,1000),
    title=hcat(NNlib.ACTIVATIONS...), titlefont=8)

Outros neurônios

\[ (x_1, \ldots, x_n) \mapsto f(w_1x_1 + \ldots + w_nx_n). \]
n = 2
m = Dense(n, 1)
Dense(2, 1)         # 3 parameters

Visualização da rede

plot(m, size=(400, 200))
Error: UndefVarError: Plots not defined

Sobre o Dense

fieldnames(Dense) # nomes dos campos do tipo composto
(:weight, :bias, :σ)
methods(Dense) # métodos para a construção do tipo composto
# 5 methods for type constructor:
[1] Flux.Dense(in::Integer, out::Integer) in Flux at /Users/rrosa/.julia/pa
ckages/Flux/7nTyc/src/layers/basic.jl:133
[2] Flux.Dense(in::Integer, out::Integer, σ; initW, initb, init, bias) in F
lux at /Users/rrosa/.julia/packages/Flux/7nTyc/src/layers/basic.jl:133
[3] Flux.Dense(W::M) where M<:(AbstractMatrix) in Flux at /Users/rrosa/.jul
ia/packages/Flux/7nTyc/src/layers/basic.jl:127
[4] Flux.Dense(W::M, bias) where M<:(AbstractMatrix) in Flux at /Users/rros
a/.julia/packages/Flux/7nTyc/src/layers/basic.jl:127
[5] Flux.Dense(W::M, bias, σ::F) where {M<:(AbstractMatrix), F} in Flux at 
/Users/rrosa/.julia/packages/Flux/7nTyc/src/layers/basic.jl:127
methods(m) # métodos definidos
# 2 methods:
[1] (a::Flux.Dense)(x::AbstractVecOrMat) in Flux at /Users/rrosa/.julia/pac
kages/Flux/7nTyc/src/layers/basic.jl:156
[2] (a::Flux.Dense)(x::AbstractArray) in Flux at /Users/rrosa/.julia/packag
es/Flux/7nTyc/src/layers/basic.jl:161
methodswith(Dense)
Error: UndefVarError: methodswith not defined
show(Docs.doc(Dense))

Dense(in, out, σ=identity; bias=true, init=glorot_uniform) Dense(W::AbstractMatrix, [bias, σ])

Create a traditional `Dense` layer, whose forward pass is given by:

y = σ.(W * x .+ bias)

The input `x` should be a vector of length `in`, or batch of vectors repres
ented as an `in × N` matrix, or any array with `size(x,1) == in`. The out `
y` will be a vector  of length `out`, or a batch with `size(y) == (out, siz
e(x)[2:end]...)`

Keyword `bias=false` will switch off trainable bias for the layer. The init
ialisation of the weight matrix is `W = init(out, in)`, calling the functio
n given to keyword `init`, with default [`glorot_uniform`](@doc Flux.glorot
_uniform). The weight matrix and/or the bias vector (of length `out`) may a
lso be provided explicitly.

# Examples

```jldoctest
julia> d = Dense(5, 2)
Dense(5, 2)         # 12 parameters

julia> d(rand(Float32, 5, 64)) |> size
(2, 64)

julia> d(rand(Float32, 5, 1, 1, 64)) |> size  # treated as three batch dime
nsions
(2, 1, 1, 64)

julia> d1 = Dense(ones(2, 5), false, tanh)  # using provided weight matrix
Dense(5, 2, tanh; bias=false)  # 10 parameters

julia> d1(ones(5))
2-element Vector{Float64}:
 0.9999092042625951
 0.9999092042625951

julia> Flux.params(d1)  # no trainable bias
Params([[1.0 1.0 … 1.0 1.0; 1.0 1.0 … 1.0 1.0]])
```
@which Dense(2,1)
Error: LoadError: UndefVarError: @which not defined
in expression starting at /Users/rrosa/Documents/git_repositories/modelagem
_matematica/src/jupyter/c04/0406-Redes_neurais.ipynb:2

Diferenças sobre a nossa implementação

l(x, h, W, b) = h.(W * x .+ b)
function (a::Dense)(x::AbstractVecOrMat)
  W, b, σ = a.weight, a.bias, a.σ
  return σ.(W*x .+ b)
end

Rede pró-alimentada

m = Chain(Dense(2, 4, σ), Dense(4, 8, tanh), Dense(8, 1, relu))
Chain(
  Dense(2, 4, σ),                       # 12 parameters
  Dense(4, 8, tanh),                    # 40 parameters
  Dense(8, 1, relu),                    # 9 parameters
)                   # Total: 6 arrays, 61 parameters, 628 bytes.
plot(m, title = "$m", titlefont = 10)
Error: UndefVarError: Plots not defined

Outros tipos de camadas