Segmentação de palavras, marcação POS e agrupamento
Marcação de sequência em ação
RNN bidirecional
BI-LSTM-CRF
Atenção
Modelos de Linguagem
Modelo de n-grama: Unigrama
Modelo de n-grama: Bigrama
Modelo de n-grama: Trigrama
Modelo de Linguagem RNN
Modelo de Linguagem Transformer
Álgebra Linear
Vetor
Matriz
Mergulhe na multiplicação de matrizes
Tensor
Crie e treine redes neurais do zero
Visão geral
Muito conhecimento teórico já foi dito antes, agora é hora de começar a prática. Vamos tentar construir uma rede neural do zero e treiná-la para encadear todo o processo.
Para ser mais intuitivo e fácil de entender, seguimos os seguintes princípios:
Não use bibliotecas de terceiros para simplificar a lógica;
Sem otimização de desempenho: evite introduzir conceitos e técnicas adicionais, aumentando a complexidade;
Conjunto de dados
Primeiro, precisamos de um conjunto de dados. Para facilitar a visualização, usamos uma função binária como função objetivo e, em seguida, geramos o conjunto de dados por amostragem nele.
Observação: em projetos de engenharia reais, a função objetivo é desconhecida, mas podemos fazer uma amostra nela.
Função objetiva
o(x,y)={10x2+y2<1otherwise
Código mostrar como abaixo:
defo(x, y):return1.0if x*x + y*y <1else0.0
Gerar conjunto de dados
sample_density =10xs =[[-2.0+4* x/sample_density,-2.0+4* y/sample_density]for x inrange(sample_density+1)for y inrange(sample_density+1)]dataset =[(x, y, o(x, y))for x, y in xs
]
O conjunto de dados gerado é: [[-2.0, -2.0, 0.0], [-2.0, -1.6, 0.0], ...]
Imagem do conjunto de dados
Construir uma rede neural
Função de ativação
import math
defsigmoid(x):return1/(1+ math.exp(-x))
Neurônio
from random import seed, random
seed(0)classNeuron:def__init__(self, num_inputs): self.weights =[random()-0.5for _ inrange(num_inputs)] self.bias =0.0defforward(self, inputs):# z = wx + b z =sum([ i * w
for i, w inzip(inputs, self.weights)])+ self.bias
return sigmoid(z)
A expressão do neurônio é:
sigmoid(wx+b)
w: vetor, correspondente ao array de pesos no código
b: corresponde ao viés no código
Nota: Os parâmetros no neurônio são inicializados aleatoriamente. No entanto, para garantir experimentos reproduzíveis, uma semente aleatória é definida(seed(0))
Redes neurais
classMyNet:def__init__(self, num_inputs, hidden_shapes): layer_shapes = hidden_shapes +[1] input_shapes =[num_inputs]+ hidden_shapes
self.layers =[[ Neuron(pre_layer_size)for _ inrange(layer_size)]for layer_size, pre_layer_size inzip(layer_shapes, input_shapes)]defforward(self, inputs):for layer in self.layers: inputs =[ neuron.forward(inputs)for neuron in layer
]# return the output of the last neuronreturn inputs[0]
Construa uma rede neural da seguinte forma:
net = MyNet(2,[4])
Neste ponto, temos uma rede neural (rede), que pode chamar sua função de rede neural:
print(net.forward([0,0]))
Obtenha o valor da função 0,55..., a rede neural neste momento é uma rede não treinada.
O cálculo do gradiente é complicado, especialmente para redes neurais profundas. Back Propagation Algorithm é um algoritmo projetado especificamente para calcular o gradiente de uma rede neural.
Devido à sua complexidade, não será descrito aqui. Os interessados podem consultar o código detalhado a seguir. Além disso, o atual framework de deep learning tem a função de calcular automaticamente o gradiente.
Encontre a derivada parcial (parte dos dados é armazenada em cache na função forward para facilitar a derivada):
classNeuron:...defforward(self, inputs): self.inputs_cache = inputs
# z = wx + b self.z_cache =sum([ i * w
for i, w inzip(inputs, self.weights)])+ self.bias
return sigmoid(self.z_cache)defzero_grad(self): self.d_weights =[0.0for w in self.weights] self.d_bias =0.0defbackward(self, d_a): d_loss_z = d_a * sigmoid_derivative(self.z_cache) self.d_bias += d_loss_z
for i inrange(len(self.inputs_cache)): self.d_weights[i]+= d_loss_z * self.inputs_cache[i]return[d_loss_z * w for w in self.weights]classMyNet:...defzero_grad(self):for layer in self.layers:for neuron in layer: neuron.zero_grad()defbackward(self, d_loss): d_as =[d_loss]for layer inreversed(self.layers): da_list =[ neuron.backward(d_a)for neuron, d_a inzip(layer, d_as)] d_as =[sum(da)for da inzip(*da_list)]
Derivadas parciais são armazenadas em d_weights e d_bias respectivamente
A função zero_grad é usada para limpar o gradiente, incluindo cada derivada parcial
A função backward é usada para calcular a derivada parcial e armazenar seu valor cumulativamente
Atualizar parâmetros
Use o método de descida de gradiente para atualizar os parâmetros:
classNeuron:...defupdate_params(self, learning_rate): self.bias -= learning_rate * self.d_bias
for i inrange(len(self.weights)): self.weights[i]-= learning_rate * self.d_weights[i]classMyNet:...defupdate_params(self, learning_rate):for layer in self.layers:for neuron in layer: neuron.update_params(learning_rate)
Realize o treinamento
defone_step(learning_rate): net.zero_grad() loss =0.0 num_samples =len(dataset)for x, y, z in dataset: predict = net.forward([x, y]) loss += square_loss(predict, z) net.backward(square_loss_derivative(predict, z)/ num_samples) net.update_params(learning_rate)return loss / num_samples
deftrain(epoch, learning_rate):for i inrange(epoch): loss = one_step(learning_rate)if i ==0or(i+1)%100==0:print(f"{i+1}{loss:.4f}")
Treinamento 2000 passos:
train(2000, learning_rate=10)
Observação: uma taxa de aprendizado relativamente grande é usada aqui, relacionada à situação do projeto. A taxa de aprendizado em projetos reais geralmente é muito pequena
Imagem da função da rede neural após o treinamento
log y
A curva de perda
Inferência
Após o treinamento, o modelo pode ser usado para inferência:
Amostragem em o(x,y) para obter o conjunto de dados, ou seja, a função do conjunto de dados: d(x,y)
Construiu uma rede neural totalmente conectada com uma camada oculta, ou seja, função de rede neural: f(x,y)
Use o método de gradiente descendente para treinar a rede neural para que f(x,y) se aproxime de d(x,y)
A parte mais complicada é encontrar o gradiente, que usa o algoritmo de retropropagação. Em projetos reais, o uso de estruturas convencionais de aprendizado profundo para desenvolvimento pode salvar o código para gradientes e diminuir o limite.
Nos experimentos de classificação 3D do laboratório, o segundo conjunto de dados é muito semelhante ao desta prática, então você pode entrar e operá-lo.