Deep Learning 03-Rede Neural Convolucional (CNN)

Introdução

CNN, ou Rede Neural Convolucional, é um modelo de aprendizado profundo comumente usado para processamento de imagens e vídeos. Em comparação com as redes neurais tradicionais, a CNN tem uma melhor capacidade de processar imagens e sequenciar dados porque pode aprender automaticamente os recursos das imagens e extrair as informações mais úteis.

Um recurso central da CNN é a operação de convolução, que pode realizar cálculos de janela deslizante na imagem e extrair recursos da imagem por meio de filtros (também chamados de kernels de convolução) e camadas de pooling (Max Pooling). A operação de convolução pode efetivamente reduzir o número de pesos e a quantidade de cálculo, ao mesmo tempo que retém as informações da estrutura espacial da imagem. A camada de pooling pode reduzir a quantidade de cálculo e melhorar a robustez do modelo sem alterar a dimensão do mapa de características.

Estruturas típicas de CNN incluem camadas convolucionais, camadas de pooling, camadas totalmente conectadas, etc. Ao mesmo tempo, para evitar ajuste excessivo, a CNN também adicionará algumas técnicas de regularização, como Dropout e regularização L2.

A CNN é amplamente utilizada na classificação de imagens, detecção de alvos, reconhecimento de fala e outros campos. Em tarefas de classificação de imagens, os modelos clássicos da CNN incluem LeNet-5, AlexNet, VGG e GoogleNet/Inception.As idéias de design e estruturas de rede desses modelos são diferentes, mas todos fizeram contribuições importantes para o desenvolvimento de redes neurais convolucionais. contribuir.

caminho de desenvolvimento

A rede neural convolucional (CNN) é um modelo de aprendizado profundo amplamente utilizado em reconhecimento de imagens, visão computacional e outros campos. No processo de desenvolvimento da CNN, surgiram muitos modelos clássicos.Aqui está uma breve introdução a vários modelos famosos.

  1. LeNet-5

LeNet-5 foi proposto por Yann LeCun e outros em 1998 e foi o primeiro modelo de rede neural convolucional amplamente utilizado. É usado principalmente para reconhecimento de dígitos manuscritos e contém camadas convolucionais, camadas de pooling e camadas totalmente conectadas. O design do LeNet-5 permite alcançar um desempenho muito bom na tarefa de reconhecimento de dígitos manuscritos MNIST. É caracterizado por um pequeno número de núcleos de convolução (6 e 16) e um pequeno número de parâmetros.A primeira camada de convolução usa 6 núcleos de convolução com tamanho de 5 × 5, e a segunda camada de convolução usa 16 Um kernel de convolução de tamanho 5×5. Esse projeto pode efetivamente reduzir o número de parâmetros do modelo, mas é o criador das redes neurais convolucionais e estabelece as bases para modelos subsequentes.

  1. Alex Net

AlexNet foi proposto por Alex Krizhevsky e outros em 2012. Foi o primeiro modelo de rede neural convolucional a alcançar excelentes resultados na competição de classificação de imagens ImageNet. Ele usa várias camadas convolucionais e camadas de pooling e usa a função de ativação ReLU e a tecnologia de regularização Dropout. O design do AlexNet o colocou significativamente à frente de outros modelos na competição de classificação de imagens ImageNet, liderando assim uma nova rodada de desenvolvimento de redes neurais convolucionais. Caracteriza-se pela utilização de um grande número de núcleos de convolução (cerca de 6.000) e um grande número de parâmetros, mas apresenta bom desempenho em termos de precisão e eficiência.

  1. VGG

O VGG foi proposto por Karen Simonyan e Andrew Zisserman em 2014. Sua principal contribuição é propor o uso de núcleos de convolução menores (3x3) em vez de núcleos de convolução maiores. Esse design torna a rede mais profunda e tem menos parâmetros, melhorando assim a eficiência e a precisão. VGG contém 16 ou 19 camadas convolucionais e camadas de pooling, e todas essas camadas usam o mesmo tamanho e avanço do kernel de convolução. O VGG obteve resultados muito bons na competição de classificação de imagens ImageNet e também forneceu inspiração para o ResNet subsequente e outros modelos.

  1. GoogleNet/Início

O GoogleNet foi proposto pela equipe do Google em 2014. Sua principal contribuição é o módulo Inception, que pode aumentar a profundidade e largura da rede sem aumentar a quantidade de parâmetros. O módulo Inception usa vários kernels de convolução e camadas de pool de tamanhos diferentes para extração de recursos e, em seguida, os conecta para formar um módulo. O GoogleNet também usa uma camada de pooling média global em vez de uma camada totalmente conectada, reduzindo ainda mais o número de parâmetros. O GoogleNet obteve resultados muito bons na competição de classificação de imagens ImageNet e também forneceu inspiração para ResNet, DenseNet e outros modelos subsequentes.

  1. ResNet

ResNet foi proposto pela equipe Microsoft Research Asia em 2015. Sua principal contribuição é propor aprendizado residual, que pode resolver o problema de degradação de redes neurais convolucionais profundas. O problema da degradação refere-se ao fenômeno de que à medida que a profundidade da rede aumenta, a precisão diminui. A aprendizagem residual evita a perda de informações ao introduzir conexões entre camadas para transferir diretamente a entrada para a saída. ResNet contém uma estrutura de rede mais profunda (152 camadas), mas atinge melhor precisão. As ideias de design do ResNet foram herdadas pelos modelos subsequentes DenseNet, MobileNet e outros modelos.

  1. DenseNet

DenseNet foi proposto por Gao Huang et al.em 2017. Sua principal contribuição é propor conexões densas, que podem aumentar a profundidade e largura da rede, melhorando assim a eficiência e a precisão. Conexão densa refere-se à conexão da saída de cada camada às entradas de todas as camadas subsequentes para formar uma estrutura de conexão densa. Esse design torna a rede mais compacta, possui menos parâmetros e também pode melhorar a capacidade de reutilização dos recursos. DenseNet obteve resultados muito bons na competição de classificação de imagens ImageNet e também serviu de inspiração para modelos subsequentes, como ShuffleNet e EfficientNet.

  1. MobileNet

MobileNet foi proposto pela equipe do Google em 2017. Sua principal contribuição é propor convolução separável em profundidade, que pode reduzir o número de parâmetros, mantendo uma boa precisão. A convolução separável em profundidade refere-se à divisão da operação de convolução em duas etapas: convolução em profundidade e convolução pontual, reduzindo assim a quantidade de cálculos e parâmetros. MobileNet usa múltiplas camadas convolucionais separáveis ​​em profundidade e camadas de pool para obter classificação eficiente de imagens e detecção de alvos em ambientes com recursos limitados, como dispositivos móveis. As ideias de design do MobileNet foram herdadas por modelos subsequentes, como ShuffleNet e EfficientNet.

  1. ShuffleNet

ShuffleNet foi proposto pela equipe Microsoft Research Asia em 2018. Sua principal contribuição é propor a reorganização de canais e convolução de grupos, o que pode reduzir significativamente a quantidade de parâmetros e cálculos, mantendo a precisão. A reorganização de canais refere-se ao agrupamento e reagrupamento de canais de entrada para permitir a troca de informações entre diferentes grupos. A convolução de grupo refere-se à divisão da operação de convolução em duas etapas: convolução intragrupo e convolução intergrupo, reduzindo assim a quantidade de cálculos e parâmetros. ShuffleNet usa reorganização de múltiplos canais e agrupa camadas convolucionais para obter classificação eficiente de imagens e detecção de alvos em ambientes com recursos limitados.

  1. EficienteNet

O EfficientNet foi proposto pela equipe do Google em 2019. Sua principal contribuição é propor escalonamento de rede e coeficientes compostos, o que pode reduzir significativamente a quantidade de parâmetros e cálculos, mantendo a precisão. O dimensionamento da rede refere-se ao dimensionamento da profundidade, largura e resolução da rede simultaneamente para otimizar sem alterar a estrutura do modelo. Os coeficientes compostos referem-se à combinação dos coeficientes de escala de profundidade, largura e resolução para obter um modelo mais eficiente. O EfficientNet obteve resultados muito bons na competição de classificação de imagens ImageNet e também forneceu inspiração para a otimização subsequente do modelo.

  1. RegNet

RegNet foi proposto pela equipe de pesquisa de IA do Facebook em 2020. Sua principal contribuição é propor regras adaptativas para a estrutura da rede, o que pode reduzir significativamente a quantidade de parâmetros e cálculos, mantendo a precisão. As regras adaptativas referem-se ao ajuste automático dos hiperparâmetros da estrutura da rede por meio de busca e otimização para obter um modelo mais eficiente. RegNet obteve resultados muito bons na competição de classificação de imagens ImageNet e também forneceu inspiração para a otimização subsequente do modelo.

Acima estão vários modelos de redes neurais convolucionais bem conhecidos, suas idéias de design e estruturas de rede são diferentes, mas todos fizeram contribuições importantes para o desenvolvimento de redes neurais convolucionais.

Princípio esquemático

As redes neurais convolucionais brilham no reconhecimento de imagens, alcançando uma precisão sem precedentes e tendo uma ampla gama de aplicações. A seguir, o reconhecimento de imagens será usado como exemplo para apresentar os princípios das redes neurais convolucionais.

Caso

Suponha que dada uma imagem (talvez a letra X ou a letra O), a CNN possa ser usada para identificar se é um X ou um O, conforme mostrado na figura abaixo, como fazer?
Insira a descrição da imagem aqui

Entrada de imagem

Se um modelo de rede neural clássico for usado, toda a imagem precisa ser lida como a entrada do modelo de rede neural (ou seja, totalmente conectada).Quando o tamanho da imagem aumentar, os parâmetros conectados a ela se tornarão muitos, resultando em uma grande quantidade de cálculo. Muito grande.
Nossa cognição humana do mundo exterior geralmente procede do local para o global. Primeiro temos uma compreensão perceptiva da parte local e, então, gradualmente adquirimos cognição do todo. Este é o modelo de compreensão humana. A conexão espacial na imagem é semelhante: os pixels na faixa local estão intimamente conectados, enquanto a correlação entre os pixels mais distantes é mais fraca. Portanto, cada neurônio não precisa realmente perceber a imagem global, ele só precisa perceber a parte local e então sintetizar a informação local em um nível superior para obter a informação global. Este modo é um artefato importante na redução do número de parâmetros em redes neurais convolucionais: o campo receptivo local.
Insira a descrição da imagem aqui

Extração de recursos

Se a letra Por exemplo, translação, dimensionamento, rotação, microdeformação, etc., conforme mostrado na figura abaixo:
Insira a descrição da imagem aqui
Nosso objetivo é identificar com precisão X e O em várias mudanças morfológicas por meio da CNN, o que envolve como extrair recursos de forma eficaz, como fator-chave para identificação.
Lembre-se do modo de "campo receptivo local" mencionado anteriormente. Para a CNN, é comparar pequenos pedaços e encontrar algumas características aproximadas (pequenas manchas de imagem) aproximadamente na mesma posição nas duas imagens. Para correspondência, em comparação com a comparação tradicional do imagem inteira, uma por uma, o método de correspondência de pequenos blocos da CNN pode comparar melhor as semelhanças entre as duas imagens. Conforme mostrado na figura
Insira a descrição da imagem aqui
: Tomando a letraabaixo
Insira a descrição da imagem aqui

Insira a descrição da imagem aqui

A extração de recursos acima é uma suposição. Na verdade, quando há várias imagens como entrada, a rede neural convolucional extrairá recursos para cada imagem. O processo específico é o seguinte: a imagem de entrada passa pela primeira camada de convolução e a convolução o kernel estará na imagem. Deslize para cima para extrair alguns recursos de baixo nível, como bordas, cantos, etc.

Em uma rede neural convolucional, se vários kernels de convolução diferentes forem usados, o tamanho do campo receptivo local de cada kernel de convolução é o mesmo, mas os pesos dos diferentes kernels de convolução são diferentes, de modo que cada kernel de convolução pode O kernel aprende recursos diferentes.

Por exemplo, suponha que usemos três núcleos de convolução diferentes na camada de convolução, onde o peso do primeiro núcleo de convolução é usado para detectar arestas, o peso do segundo núcleo de convolução é usado para detectar recursos de textura e o peso do terceiro núcleo de convolução kernel é usado para detectar bordas.Os pesos dos kernels de convolução são usados ​​para detectar a forma do alvo. Os campos receptivos locais desses três núcleos de convolução são todos do mesmo tamanho, mas como seus pesos são diferentes, cada núcleo de convolução pode aprender recursos diferentes.

Deve-se notar que o tamanho e o tamanho do passo do kernel de convolução também afetarão o tamanho do campo receptivo local de cada kernel de convolução. Se o tamanho do núcleo de convolução for maior, seu campo receptivo local também se tornará maior; se o tamanho do passo for maior, a distância que o núcleo de convolução desliza a cada vez também se tornará maior, afetando assim o núcleo de convolução. campo receptivo local.

Por exemplo, kernel de convolução
[-1, 0, 1],
[-1, 0, 1],
[-1, 0, 1]]

Esta matriz é na verdade um kernel de convolução, também conhecido como filtro Sobel. Pode ser usado para detectar bordas verticais em imagens.
Na visão computacional, as bordas referem-se a áreas de uma imagem com grandes alterações no valor de cinza. As bordas verticais referem-se à mudança no valor de cinza da parte superior para a parte inferior da imagem ou da parte inferior para a parte superior.
O princípio de funcionamento do kernel de convolução é envolvê-lo com os pixels da imagem para extrair as características da imagem. Neste exemplo, o elemento central do kernel de convolução é 0, indicando que não tem nada a ver com o pixel central da imagem. A linha superior de elementos [-1, 0, 1] do kernel de convolução indica que ele realiza uma operação de convolução com os pixels superiores da imagem. Da mesma forma, os elementos da linha inferior do kernel de convolução [-1, 0, 1] indicam que ele realiza uma operação de convolução com os pixels inferiores da imagem.

Quando o núcleo de convolução é convolucionado com pixels na imagem, se houver bordas verticais na imagem, os resultados da convolução mostrarão mudanças óbvias. Especificamente, em um lado da aresta vertical, o resultado da convolução obterá um valor positivo maior, enquanto no outro lado da aresta vertical, o resultado da convolução obterá um valor negativo maior. Desta forma, podemos identificar as bordas verticais da imagem através dos resultados da convolução limite, e as partes negativas são retornadas diretamente para 0.

Por exemplo, digamos que temos uma imagem onde parte dela é uma borda vertical. Aplicamos o kernel de convolução à parte da borda vertical desta imagem, e o resultado da convolução mostrará valores positivos e negativos, para que possamos extrair a posição da borda vertical limitando o resultado da convolução.

Espero que este exemplo possa ajudá-lo a entender por que a matriz [-1, 0, 1] pode ser usada para detectar arestas verticais.
Outro exemplo é
[[-0,1111, -0,1111, -0,1111],
[-0,1111, 1,0000, -0,1111],
[-0,1111, -0,1111, -0,1111]],
que é chamado de filtro Laplaciano ou filtro de nitidez. Ele pode ser usado para aprimorar bordas em imagens.
Nesta matriz, o elemento central 1 significa que está relacionado ao pixel central da imagem. E os elementos circundantes -0,1111 significam que estão relacionados aos pixels circundantes da imagem.

Quando o núcleo de convolução é convolvido com a imagem, o valor do pixel central será amplificado, enquanto o valor dos pixels circundantes será suprimido. Desta forma, na borda da imagem, devido às grandes alterações nos valores dos pixels, o resultado da convolução apresentará valores positivos e negativos maiores, aumentando assim o contraste da borda.

Por exemplo, digamos que temos uma imagem que contém algumas arestas. Aplicamos esse núcleo de convolução à imagem, e o resultado da convolução aumentará o contraste das bordas, tornando-as mais nítidas.

Portanto, este kernel de convolução pode detectar arestas e torná-las mais óbvias, aumentando o contraste das arestas.

borda

A borda é o local onde o valor de cinza do pixel na imagem muda significativamente. Geralmente representa informações como borda, contorno ou textura do objeto na imagem. No processamento de imagens e na visão computacional, a detecção de bordas é uma técnica comumente usada que pode ser usada para segmentar imagens, extrair recursos, etc.
Por exemplo, conforme mostrado abaixo,
Insira a descrição da imagem aqui
o efeito da extração de bordas
Insira a descrição da imagem aqui

ponto de canto

Os pontos de canto são pontos especiais em áreas locais da imagem com mudanças óbvias de ângulo. Os pontos de canto geralmente são formados pela intersecção de arestas em diferentes direções, possuem curvatura gaussiana e são uma das características importantes nas imagens. A detecção de cantos também é uma tecnologia comumente usada em registro de imagens, rastreamento de objetos, correspondência de imagens, etc. Algoritmos de detecção de canto comumente usados ​​incluem detecção de canto Harris, detecção de canto Shi-Tomasi, etc.
Como mostrado abaixo
Insira a descrição da imagem aqui

opencv

OpenCV (Open Source Computer Vision Library) é uma biblioteca de software de código aberto de visão computacional e aprendizado de máquina. Ele pode ajudar os desenvolvedores a construir rapidamente aplicativos de visão computacional, como processamento de imagens, detecção de objetos, reconhecimento facial, análise de vídeo, etc.

OpenCV foi originalmente iniciado pela Intel Corporation e agora se tornou um projeto de código aberto multiplataforma que suporta múltiplas linguagens de programação, incluindo C++, Python, Java, etc., e pode ser executado em sistemas operacionais como Windows, Linux, macOS, etc.

Opencv é usado aqui para extrair as bordas e cantos de uma determinada imagem. Por exemplo, a imagem é
Insira a descrição da imagem aqui

Não entrarei em detalhes sobre o opencv aqui, explicarei mais adiante no artigo.
código

#%%
import cv2  #注意安装open-cv  conda install open-cv
import numpy as np
import matplotlib.pyplot as plt

# 读入lena图像
img = cv2.imread('d:/9.png')
# 将BGR图像转换为RGB图像,便于matplotlib显示
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# 将图像转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
gray_ori=gray
# 使用Canny边缘检测函数检测图像的边缘
edges = cv2.Canny(gray, 100, 200)

# 创建SIFT对象
sift = cv2.xfeatures2d.SIFT_create()
# 检测图像的特征点
keypoints = sift.detect(gray, None)
# 在图像上绘制特征点
img_sift = cv2.drawKeypoints(img, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

# 检测图像的角点
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
# 将角点标记为红色
img_corner = img.copy()
img_corner[dst > 0.01 * dst.max()] = [255, 0, 0]

# 创建一个Matplotlib窗口并显示图像及其各种特征
plt.rcParams['font.family'] = 'SimHei'
fig, axs = plt.subplots(2, 2, figsize=(10, 10))
axs[0, 0].imshow(img)
axs[0, 0].set_title('原始图像')
axs[0, 1].imshow(edges, cmap='gray')
axs[0, 1].set_title('边缘')
axs[1, 0].imshow(img_sift)
#SIFT的全称是Scale Invariant Feature Transform,尺度不变特征变换。具有旋转不变性、尺度不变性、亮度变化保持不变性,是一种非常稳定的局部特征。
axs[1, 0].set_title('SIFT特征')
axs[1, 1].imshow(img_corner)
axs[1, 1].set_title('角点特征')
plt.show()

Efeito de saída
Insira a descrição da imagem aqui

Princípio de extração de recursos

Por favor, leia esta seção depois de ler o capítulo [Convolução]
.Kernels de convolução comumente usados ​​incluem o seguinte:

  1. Filtro Gaussiano: usado para suavização de imagem, o que pode reduzir o ruído da imagem.
  2. Filtro passa-alta: usado para destacar informações de alta frequência na imagem, como bordas, cantos, etc.
  3. Filtro passa-baixa: usado para destacar informações de baixa frequência na imagem, como desfoque, suavização, etc.
  4. Filtro Sobel: usado para detectar informações de borda em imagens.
  5. Filtro Laplaciano: usado para aprimorar informações de alta frequência das imagens, como bordas, detalhes, etc.
  6. Filtro Scharr: semelhante ao filtro Sobel, mas mais responsivo às bordas.
  7. Filtro Prewitt: Semelhante ao filtro Sobel, mas tem uma resposta mais suave às bordas.

Esses kernels de convolução podem ser usados ​​para diferentes tarefas no processamento de imagens, como detecção de bordas, suavização de imagens, aprimoramento de imagens, etc. Você pode escolher kernels de convolução apropriados para processar imagens com base em diferentes tarefas.

O kernel de convolução definido abaixo pode ser considerado um filtro passa-alta, porque seu pixel central recebe um peso maior e os pixels adjacentes têm pesos menores. Essa distribuição de peso permite que o kernel de convolução detecte informações de alta frequência na imagem, como bordas, cantos, etc. Na operação de convolução, o núcleo de convolução é multiplicado por cada pixel da imagem e os resultados são somados para obter um novo valor de pixel. Se a diferença entre os valores dos pixels ao redor do pixel central do kernel de convolução e o valor do pixel central for grande, o resultado da operação de convolução será maior, indicando que este pixel pode ser um ponto de borda. Portanto, este kernel de convolução pode destacar informações de borda na imagem.

kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])

Há a seguinte imagem:
Insira a descrição da imagem aqui
use opencv para carregá-lo e convoluí-lo com um kernel de convolução.

import cv2
import numpy as np
from myutils.common import show,fillColor
# 读取图片
img = cv2.imread('./images/z.png')

# 将图像转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 定义卷积核
kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
# kernel = np.array([[-1,-1,-1,-1,-1],[-1,-1,-1,-1,-1], [-1,-1,20,-1,-1],[-1,-1,-1,-1,-1], [-1,-1,-1,-1,-1]])
# kernel = cv2.getGaussianKernel(5, 1)

# 对灰度图像进行卷积操作,#注意如果-1 <0的值会被归一化为0
edges = cv2.filter2D(gray, cv2.CV_32F, kernel)
print(edges[:][edges<0])
# 对卷积结果进行ReLU处理
edges_relu = np.maximum(0, edges)
show(img,'Original Image',cmap="gray",debug=True)  
show(edges, 'Edges Image',cmap="gray",debug=True)
show(edges_relu, 'Edges ReLU Image',cmap="gray",debug=True)

def show(dilate, title, cmap=None, debug=False):
    if debug:
        plt.title(title)
        plt.imshow(dilate, cmap=cmap)
        plt.show()

Insira a descrição da imagem aqui

Por que se diz que a operação de convolução extrai características lineares em vez de usar relu?

Tomemos um exemplo simples para ilustrar que a própria operação de convolução não pode extrair características não lineares.

Suponha que temos uma matriz de entrada X contendo os seguintes valores:

X = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Agora, usamos um kernel de convolução K de tamanho 2x2 para convolver X. O valor do kernel de convolução é o seguinte:

K = [[1, 1], [1, 1]]

Podemos usar a multiplicação de matrizes para realizar operações de convolução. Especificamente, invertemos a matriz K e realizamos uma operação de produto escalar com a matriz X para obter uma matriz de saída Y:

Y = K*X = [[12, 16], [24, 28]]

Pode-se observar que a matriz de saída Y é uma combinação linear da matriz de entrada X, portanto a própria operação de convolução só pode extrair características lineares da matriz de entrada X, como bordas e texturas.

No entanto, quando usamos uma função de ativação não linear, como a função de ativação ReLU, para processar a matriz de saída Y, podemos converter recursos lineares em recursos não lineares. Por exemplo, quando aplicamos a função ReLU a Y, as características não lineares resultantes são:

ReLU(Y) = [[12, 16], [24, 28]]

Portanto, a operação de convolução por si só pode extrair recursos lineares da matriz de entrada, mas quando combinada com uma função de ativação não linear, os recursos não lineares podem ser extraídos.

convolução

Então, como esses recursos são calculados para correspondência? (Não me diga que os pixels são combinados um por um, suor!)
Neste momento, temos que convidar o convidado importante de hoje: a convolução. Então, o que é convolução? Não se preocupe, explicarei isso lentamente abaixo.
Quando uma nova imagem é fornecida, a CNN não sabe exatamente quais partes da imagem original esses recursos precisam corresponder, então tentará todas as posições possíveis na imagem original, o que equivale a transformar esse recurso em um filtro. Esse processo de correspondência é chamado de operação de convolução, que também é a origem do nome da rede neural convolucional.
A operação de convolução é mostrada na figura abaixo:
Insira a descrição da imagem aqui

A parte amarela é um kernel de convolução, ou seja, os recursos extraídos da imagem anterior
[[1,0,1]
[0,1,0]
[1,0,1]]
são iguais a todos os 3* possíveis em a imagem 3 imagens são calculadas (convolução na mesma posição multiplicada e depois somada / o número atual de matrizes de agregação é 9), o resultado do cálculo é um número colocado no centro da convolução atual e, finalmente, um novo é obtido com a camada mais externa removida.matriz, consulte o seguinte para lógica de cálculo específica.

Neste caso, para calcular um recurso (recurso) e o resultado de um determinado pequeno patch correspondente a ele na imagem original, basta multiplicar os valores dos pixels nas posições correspondentes nos dois pequenos patches e, em seguida, multiplicar todo o pequeno patch. Os resultados da operação são acumulados e finalmente divididos pelo número total de pixels no pequeno bloco (nota: não é necessário dividir pelo número total).
Se ambos os pixels forem brancos (ambos têm valor 1), então 1 1 = 1, se ambos forem pretos, então (-1) (-1) = 1, ou seja, cada par de pixels pode corresponder, o resultado da multiplicação é 1. Da mesma forma, quaisquer pixels não correspondentes são multiplicados por -1. O processo específico é o seguinte (resultados correspondentes do primeiro, segundo..., último pixel):
Primeiro, use um dos três recursos que extraímos anteriormente para convolução
Insira a descrição da imagem aqui
, por exemplo, circule o primeiro recurso com uma moldura verde Comparação de partes é exatamente o mesmo.
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
Insira a descrição da imagem aqui
De acordo com o método de cálculo da convolução, o cálculo da convolução após a primeira correspondência de recurso é o seguinte e o resultado é 1. A
Insira a descrição da imagem aqui
correspondência de outras posições também é semelhante (como a correspondência da parte intermediária)
Insira a descrição da imagem aqui
e assim por diante. Para os três A imagem de recurso repete continuamente o processo acima. Através da operação de convolução de cada recurso (recurso), uma nova matriz bidimensional será obtida, chamada de mapa de recursos ( mapa de recursos ) . Quanto mais próximo o valor estiver de 1, mais completa será a correspondência entre a posição correspondente e o recurso. Quanto mais próximo estiver de -1, mais completa será a correspondência entre a posição correspondente e o lado oposto do recurso. Quanto mais próximo for o valor. for 0, mais completa será a correspondência entre a posição correspondente e o recurso. Quanto mais próximo o valor estiver de 0, mais completa será a correspondência entre a posição correspondente e o recurso. Conforme mostrado na figura abaixo:
Insira a descrição da imagem aqui
Pode-se observar que quando o tamanho da imagem aumenta, o número de operações internas de adição, multiplicação e divisão aumentará muito rapidamente, e o tamanho de cada filtro e o número de filtros crescerão linearmente. Com tantos fatores em jogo, a quantidade de cálculos pode facilmente tornar-se bastante grande.

Agrupamento

Para reduzir efetivamente a quantidade de cálculo, outra ferramenta eficaz utilizada pela CNN é chamada de “Pooling”. Pooling serve para diminuir a imagem de entrada, reduzir as informações de pixel e reter apenas informações importantes.
A operação de pooling também é muito simples: normalmente, a área de pooling tem tamanho 2 2 e depois é convertida em valores correspondentes de acordo com certas regras, como tomar o valor máximo (max-pooling) e a média (média) na área de pooling, -pooling), etc., use esse valor como o valor de pixel resultante.
A figura abaixo mostra
o resultado do pooling máximo da área de pooling 2 2 no canto superior esquerdo. Tome o máximo max(0,77,-0,11,-0,11,1,00) desta área como o resultado do pool, conforme mostrado na figura abaixo : Agrupando a área à
Insira a descrição da imagem aqui
esquerda, o segundo bloco pequeno assume o valor máximo máximo (0,11, 0,33, -0,11, 0,33) como resultado após o agrupamento, conforme mostrado abaixo: As outras
Insira a descrição da imagem aqui
áreas são semelhantes, assumindo o valor máximo na área como o resultado após o pooling e, finalmente, após o pooling, o resultado é o seguinte:
Insira a descrição da imagem aqui
execute a mesma operação em todos os mapas de recursos, o resultado é o seguinte:
Insira a descrição da imagem aqui
max-pooling retém o valor máximo em cada bloco pequeno, o que equivale a reter o melhor valor deste bloco.O resultado da correspondência (uma vez que um valor mais próximo de 1 significa uma melhor correspondência). Em outras palavras, ele não focará especificamente em qual local da janela é correspondido, mas apenas se há uma correspondência em algum lugar.
Ao adicionar uma camada de pooling, a imagem é reduzida, o que pode reduzir bastante a quantidade de cálculo e a carga da máquina.

Função de ativação ReLU (Unidades Lineares Retificadas)

As funções de ativação comumente usadas incluem sigmóide, tanh, relu, etc. As duas primeiras, sigmóide/tanh, são mais comuns em camadas totalmente conectadas, e a última, ReLU, é comum em camadas convolucionais.
Olhando para trás, para o perceptron mencionado anteriormente, o perceptron recebe cada entrada, soma-a e emite-a após passar pela função de ativação. A função da função de ativação é adicionar fatores não lineares e realizar mapeamento não linear dos resultados de saída da camada de convolução.
Insira a descrição da imagem aqui
Em redes neurais convolucionais, a função de ativação geralmente usa ReLU (The Rectified Linear Unit, unidade linear modificada), que é caracterizada por convergência rápida e cálculo simples de gradiente. A fórmula de cálculo também é muito simples, max(0,T), ou seja, para valores de entrada negativos, a saída é toda 0, e para valores positivos, a saída permanece inalterada.
Vamos dar uma olhada no processo de operação da função de ativação ReLU neste caso:
o primeiro valor é considerado max(0,0,77) e o resultado é 0,77, conforme mostrado abaixo. O
Insira a descrição da imagem aqui
segundo valor é considerado max(0,0,77), -0,11), e o resultado é 0, conforme mostrado abaixo Figura
Insira a descrição da imagem aqui
Por analogia, depois de passar pela função de ativação ReLU, os resultados são os seguintes:
Insira a descrição da imagem aqui
Execute a operação da função de ativação ReLU em todos os mapas de recursos e os resultados são os seguintes:
Insira a descrição da imagem aqui

rede neural profunda

Ao combinar a convolução, função de ativação e pooling mencionados acima, obtém-se a seguinte figura:
Insira a descrição da imagem aqui
Ao aumentar a profundidade da rede e adicionar mais camadas, obtém-se uma rede neural profunda, conforme mostrado abaixo:
Insira a descrição da imagem aqui

Camadas totalmente conectadas

A camada totalmente conectada desempenha o papel de “classificador” em toda a rede neural convolucional, ou seja, após passar por redes profundas como convolução, função de ativação e pooling, os resultados são identificados e classificados através da camada totalmente conectada.
Primeiro, os resultados da rede profunda após convolução, função de ativação e pooling são interligados, conforme mostrado na figura abaixo:
Insira a descrição da imagem aqui
Como a rede neural pertence ao aprendizado supervisionado, durante o treinamento do modelo, o modelo é treinado com base nas amostras de treinamento para obter um peso totalmente conectado da camada (como o peso de todas as conexões prevendo a
Insira a descrição da imagem aqui
letra Os resultados calculados são ponderados e somados para obter o valor previsto de cada resultado e então o maior valor é considerado o resultado do reconhecimento (como mostrado na figura abaixo, o valor final de reconhecimento calculado da letra X é 0,92 e o valor de reconhecimento da letra O é 0,51, então O resultado é
Insira a descrição da imagem aqui
considerado
Insira a descrição da imagem aqui

Redes Neurais Convolucionais

Depois de reunir todos os resultados acima, uma estrutura de "Rede Neural Convolucional" (CNN) é formada, conforme mostrado na figura abaixo: Finalmente, para
Insira a descrição da imagem aqui
revisar e resumir, a rede neural convolucional consiste principalmente em duas partes, uma parte é extração de recursos (convolução, função de ativação, pooling), e a outra parte é o reconhecimento de classificação (camada totalmente conectada).A figura a seguir é o famoso diagrama de estrutura de rede neural convolucional de reconhecimento de texto manuscrito:
Insira a descrição da imagem aqui

Referência para o conteúdo deste capítulo: https://my.oschina.net/u/876354/blog/1620906

API de convolução

Conv2D

Conv2D é uma das camadas principais das redes neurais convolucionais e é uma camada usada para processamento convolucional de imagens ou outros dados bidimensionais. A função do Conv2D é realizar uma série de operações de convolução na imagem ou dados bidimensionais de entrada por meio do kernel de convolução, extraindo assim os recursos da imagem ou dos dados.

A entrada da camada Conv2D é um tensor. A forma do tensor é geralmente (batch_size, altura, largura, canal), onde batch_size representa o número de dados de entrada, altura e largura representam a altura e largura dos dados de entrada, e canal representa o número de canais dos dados de entrada (por exemplo, o número de canais de uma imagem RGB é 3).

A saída da camada Conv2D também é um tensor, que representa o mapa de características obtido após a operação de convolução. A forma do tensor de saída é geralmente (batch_size, conv_height, conv_width, filtros), onde conv_height e conv_width representam a altura e largura do mapa de recursos obtido após a aplicação do kernel de convolução, e os filtros representam o número de kernels de convolução, ou seja , o número de canais do mapa de recursos de saída.

Durante o processo de convolução, a camada Conv2D aplica o kernel de convolução aos dados de entrada e obtém o mapa de recursos de saída convoluto calculando a operação de convolução entre cada kernel de convolução e os dados de entrada, um por um. Durante o processo de convolução, parâmetros como tamanho, tamanho do passo e método de preenchimento do kernel de convolução podem ser definidos livremente para se adaptarem a diferentes cenários de aplicação.
No TensorFlow 2.0 e Keras, você pode criar uma camada Conv2D com o seguinte código:

from tensorflow.keras.layers import Conv2D

conv_layer = Conv2D(filters=32, kernel_size=(3, 3), strides=(1, 1), padding='same', activation='relu', input_shape=(height, width, channel))
  • filtros: o número de kernels de convolução, ou seja, o número de mapas de recursos de saída.
  • kernel_size: O tamanho do kernel de convolução, que pode ser um número inteiro, representando o comprimento lateral de um kernel de convolução quadrado, ou uma tupla, representando kernels de convolução com diferentes comprimentos e larguras.
  • passos: passos, que é a distância que o kernel de convolução se move no mapa de recursos de entrada. Pode ser um número inteiro, indicando a distância entre dois núcleos de convolução adjacentes, ou pode ser uma tupla, indicando que o tamanho do passo é diferente nas direções de comprimento e largura.
  • padding: método de preenchimento, pode ser 'mesmo' ou 'válido'. 'mesmo' significa que o tamanho do mapa de recursos de saída é igual ao tamanho do mapa de recursos de entrada e alguns valores precisam ser preenchidos ao redor do mapa de recursos de entrada; 'válido' significa que nenhum preenchimento é necessário e o tamanho do mapa de recursos de saída será baseado no mapa de recursos de entrada e no kernel de convolução. varia com o tamanho.
  • ativação: função de ativação, usada para adicionar transformação não linear ao mapa de recursos. Funções de ativação comuns incluem 'relu', 'sigmoid', 'tanh', etc.
  • input_shape: A forma do mapa de recursos de entrada, que pode ser um trio representando altura, largura e número de canais. Este parâmetro precisa ser especificado na primeira camada convolucional.
  • kernel_regularizer: Na aprendizagem profunda, a fim de evitar o sobreajuste do modelo, a tecnologia de regularização é geralmente usada para restringir o modelo.Um dos métodos de regularização comumente usados ​​é a regularização L2. A regularização L2 refere-se à adição de um termo de penalidade da norma L2 à função de perda do modelo para limitar o tamanho do peso do modelo.
    Em Keras, use regularizers.l2(0.001) para adicionar uma penalidade de regularização L2. Dentre eles, 0,001 é o parâmetro de regularização, que controla a força da regularização. Quanto maior o parâmetro de regularização, maior será o impacto do termo de penalidade no peso, e a complexidade do modelo será reduzida, evitando efetivamente o sobreajuste.
    Especificamente, regularizers.l2(0.001) pode ser aplicado a qualquer matriz de peso em redes neurais, como camadas totalmente conectadas, camadas convolucionais, etc. Na definição da rede, podemos adicionar a regularização L2 usando o parâmetro kernel_regularizer na camada correspondente. Por exemplo, o código para adicionar uma camada totalmente conectada com regularização L2 em Keras é o seguinte:
layers.Conv2D(32, (3, 3), activation='relu', kernel_regularizer=regularizers.l2(0.001), input_shape=(28, 28, 1)),

Exemplo de convolução

Tire fotos do minist10 e use 10 núcleos de convolução para convolução, produza mapas de recursos e exiba a imagem.
Como cada imagem gerará 10 núcleos de convolução, um total de 100 mapas de recursos serão gerados.

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

# 加载mnist数据集
mnist = tf.keras.datasets.mnist
(train_images, train_labels), (test_images, test_labels) = mnist.load_data()

# 取1张训练集图片
images = train_images[:10]

# 将图片转换为float类型
images = images.astype('float32') / 255.0
# 将图片reshape成4D张量,大小为(10, 28, 28, 1),也就是第一个维度表示有10张图像,每张图像由28行、28列和1个# 通道(灰度)组成
images = np.expand_dims(images, axis=3)
# 定义卷积核数量
num_filters = 10

# 定义卷积层
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(num_filters, (3, 3), activation='relu', input_shape=(28, 28, 1)),
])

# 计算卷积后的特征图
features = model.predict(images)

# 绘制卷积后的特征图
fig, axs = plt.subplots(nrows=num_filters, ncols=10, figsize=(10, num_filters))
for i in range(num_filters):
    for j in range(10):
        axs[i][j].imshow(features[j, :, :, i], cmap='gray')
        axs[i][j].axis('off')
plt.show()

saída
Insira a descrição da imagem aqui

A função np.expand_dims é usada para expandir as dimensões de uma matriz no eixo especificado. Neste exemplo, imagens é uma matriz de formas (10, 28, 28), representando 10 imagens em tons de cinza 28x28. No entanto, os modelos de aprendizado de máquina geralmente precisam inserir uma matriz quadridimensional, ou seja, (número de amostras, altura da imagem, largura da imagem, número de canais). Portanto, precisamos expandir a última dimensão (número de canais) do array de imagens em uma dimensão e transformá-lo em um array de formato (10, 28, 28, 1).
Especificamente, axis=3 significa expandir as dimensões no 3º eixo da matriz (contando a partir de 0), o que adiciona uma dimensão à última dimensão de cada imagem, transformando cada imagem em uma forma de (28, 28, 1) três- matriz dimensional. Finalmente, o formato da matriz de imagens passa a ser (10, 28, 28, 1), o que significa que existem 10 imagens em tons de cinza 28x28, cada imagem consiste em um canal. Dessa forma, as imagens podem ser passadas como entrada para o modelo de aprendizado de máquina.

Como pode ser visto na imagem de saída acima, a saída de alguns núcleos de convolução é direcionada para bordas, alguns cantos e algumas texturas.

MaxPooling2D

keras.layers.MaxPooling2D((2, 2)) é uma camada no Keras usada para operações máximas de pooling.
O pooling máximo é uma operação de rede neural convolucional comumente usada que pode reduzir o número de parâmetros em uma imagem sem alterar o tamanho da imagem, reduzindo assim a quantidade de cálculo e o consumo de memória. A operação de pooling máximo divide a imagem de entrada em blocos não sobrepostos e assume o valor máximo de cada bloco como saída. Em redes neurais convolucionais, o pooling máximo é geralmente usado de forma intercambiável com camadas convolucionais para extrair características espaciais de imagens.

O parâmetro da camada MaxPooling2D é uma tupla (2, 2), indicando que o tamanho da janela de pooling é 2x2. Isso significa que a imagem de entrada será dividida em vários blocos de tamanho 2x2, e o valor máximo de cada bloco será considerado como saída. Se o tamanho da janela de pooling for definido como (3, 3), a imagem de entrada será dividida em vários blocos de tamanho 3x3 e o valor máximo de cada bloco será considerado como saída.

Resumindo, a camada MaxPooling2D pode ajudar a rede neural convolucional a extrair os recursos espaciais da imagem, ao mesmo tempo que reduz a quantidade de cálculo e o consumo de memória.

Achatar

keras.layers.Flatten() é uma camada em Keras que é usada para "achatar" a entrada em um vetor unidimensional.

Em uma rede neural convolucional, camadas convolucionais e camadas de pooling são geralmente usadas para extrair recursos de imagens e, em seguida, camadas totalmente conectadas são usadas para classificação. A entrada da camada totalmente conectada é um vetor unidimensional, portanto, o mapa de recursos anterior precisa ser "achatado" em um vetor unidimensional. Isto é o que a camada Flatten faz.

A camada Flatten não possui nenhum parâmetro, apenas desdobra o tensor de entrada em um vetor unidimensional em ordem. Por exemplo, se o tensor de entrada tiver formato (batch_size, 7, 7, 64), o formato de saída da camada Flatten será (batch_size, 7 7 64 ).

Ao construir uma rede neural convolucional, uma camada Flatten é geralmente adicionada após a camada convolucional e a camada de pooling para nivelar o mapa de recursos em um vetor unidimensional e, em seguida, conectá-lo à camada totalmente conectada para classificação.

Denso | Abandono

Veja perceptron multicamadas

Reconhecimento de dígitos manuscritos

Conjunto de dados mnist convolucional

Carregaremos o conjunto de dados MNIST e o pré-processamento, dimensionaremos os valores dos pixels entre 0 e 1 e dividiremos o conjunto de dados em conjuntos de treinamento e teste.
Para uma explicação detalhada do processamento de dados, consulte o perceptron multicamadas.

import tensorflow as tf
import tensorflow.keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras import regularizers
(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.

x_train = x_train[..., tf.newaxis]
x_test = x_test[..., tf.newaxis]

num_classes = 10

y_train = tf.keras.utils.to_categorical(y_train, num_classes)
y_test = tf.keras.utils.to_categorical(y_test, num_classes)

A seguir, definiremos um modelo de rede neural convolucional. Usaremos duas camadas convolucionais e duas camadas de pooling, seguidas por duas camadas totalmente conectadas e uma camada de saída. Também usaremos dropout e regularização L2 para evitar overfitting.

model = tf.keras.Sequential([
    layers.Conv2D(32, (3, 3), activation='relu', kernel_regularizer=regularizers.l2(0.001), input_shape=(28, 28, 1)),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu', kernel_regularizer=regularizers.l2(0.001)),
    layers.MaxPooling2D((2, 2)),
    layers.Flatten(),
    layers.Dense(128, activation='relu', kernel_regularizer=regularizers.l2(0.001)),
    layers.Dropout(0.5),
    layers.Dense(64, activation='relu', kernel_regularizer=regularizers.l2(0.001)),
    layers.Dropout(0.5),
    layers.Dense(num_classes, activation='softmax')
])

model.summary() é um método do objeto modelo em Keras, usado para imprimir as informações estruturais do modelo, incluindo o nome de cada camada, formato de saída, número de parâmetros, etc. Isso é útil para depuração, otimização do modelo e compreensão da estrutura do modelo.

model.summary()

Em seguida, compilaremos o modelo e usaremos técnicas de aumento de dados para evitar ainda mais o overfitting. A tecnologia de aumento de dados aplicará uma série de transformações aleatórias, como rotação, translação, escalonamento, etc., para gerar novas amostras de treinamento. Isso torna o modelo mais robusto e evita overfitting.

model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])

datagen = ImageDataGenerator(
    rotation_range=10,
    width_shift_range=0.1,
    height_shift_range=0.1,
    zoom_range=0.1
)

A seguir, usaremos o conjunto de treinamento para treinar o modelo e o conjunto de testes para avaliar o desempenho do modelo.

datagen.fit(x_train)
batch_size = 1024
epochs = 10
checkpoint = tf.keras.callbacks.ModelCheckpoint('./model.h5', save_best_only=True, save_weights_only=False, monitor='val_loss')
history = model.fit(datagen.flow(x_train, y_train, batch_size=batch_size),
                    epochs=epochs,
                    validation_data=(x_test, y_test),
                    steps_per_epoch=len(x_train) // batch_size,callbacks=[checkpoint])

score = model.evaluate(x_test, y_test, verbose=0)
print('Test loss:', score[0])
print('Test accuracy:', score[1])

A diferença entre steps_per_epoch e batch_size
é que batch_size se refere ao número de amostras incluídas em cada lote de treinamento (lote). No aprendizado profundo, o conjunto de treinamento geralmente é dividido em vários lotes, cada lote contendo diversas amostras. A vantagem disso é que as operações matriciais podem ser usadas para acelerar os cálculos, e a ordem das amostras também pode ser interrompida aleatoriamente durante o processo de treinamento para evitar ajuste excessivo.

steps_per_epoch refere-se ao número de lotes que o modelo precisa ser treinado em uma época. Como cada época contém vários lotes, steps_per_epoch precisa ser definido para especificar quantos lotes precisam ser passados ​​em uma época. Normalmente, o valor de steps_per_epoch pode ser calculado a partir do tamanho do conjunto de treinamento e do batch_size. Por exemplo, se o tamanho do conjunto de treinamento for 1.000 e batch_size for 32, então 1.000/32 = 31 lotes precisam ser treinados em uma época, portanto, steps_per_epoch deve ser definido como 31.

Deve-se observar que steps_per_epoch não é necessariamente igual ao tamanho do conjunto de treinamento dividido por batch_size. Se o tamanho do conjunto de treinamento não for divisível por batch_size, o último lote poderá conter menos amostras de batch_size. Para evitar esta situação, você pode usar a operação de arredondamento para baixo // para calcular steps_per_epoch para garantir que todo o conjunto de treinamento possa ser processado em cada época.

afinação

O ajuste fino refere-se ao método de ajuste fino de um modelo já treinado para tarefas específicas ou conjuntos de dados específicos para obter melhor desempenho. Normalmente, usaremos um modelo pré-treinado em um conjunto de dados de grande escala, como ImageNet e outros conjuntos de dados.Este modelo aprendeu muitos recursos e padrões comuns durante o processo de treinamento. Podemos ajustar este modelo, ajustar alguns parâmetros ou adicionar novas camadas para tornar este modelo mais adequado para novas tarefas ou novos conjuntos de dados. Essa abordagem geralmente é mais eficiente do que treinar um modelo do zero porque o modelo pré-treinado já possui bons pesos iniciais e recursos de extração de recursos.

conjunto de dados mnist-c

MNIST-C é uma variante do conjunto de dados MNIST, que é um conjunto de dados MNIST com ruído artificial adicionado. O conjunto de dados MNIST é um conjunto de dados de reconhecimento de dígitos manuscritos contendo 60.000 amostras de treinamento e 10.000 amostras de teste, cada amostra é uma imagem em escala de cinza de 28 x 28 pixels. O conjunto de dados MNIST-C é criado adicionando ruído aleatório às imagens do conjunto de dados MNIST.Esses ruídos incluem desfoque, distorção, alterações de brilho, etc., tornando o modelo mais robusto.

O conjunto de dados MNIST-C é muito útil para testar a robustez de modelos de aprendizado de máquina porque pode testar a robustez do modelo para diferentes tipos de ruído. Cada imagem no conjunto de dados MNIST-C contém um rótulo que indica o número que representa. Esses rótulos são idênticos aos rótulos correspondentes no conjunto de dados MNIST, portanto, você pode usar o mesmo processo de treinamento e teste para treinar e testar seu modelo.

Faça download do conjunto de dados em https://github.com/google-research/mnist-c/. Este endereço do github é o endereço do código-fonte. O endereço de download real é mencionado no leia-me: https://zenodo.org/record /3239543# .ZF2rzXZByUl, baixe e descompacte.Essas
Insira a descrição da imagem aqui
pastas são todas exportações de array numpy no formato npy.
Leia as primeiras 10 fotos de cada pasta para exibir

# 数据集的开源地址:https://github.com/google-research/mnist-c/
import os
import numpy as np
import matplotlib.pyplot as plt
#加载数据集并打印每个子文件夹前10个数据集
data_root = './mnist_c'
dirlist=os.listdir(data_root)
fig, axs = plt.subplots(len(dirlist), 10, figsize=(10, 10))

for i, folder_name in enumerate(dirlist):
    folder_path = os.path.join(data_root, folder_name)
    if os.path.isdir(folder_path):
        file_path = os.path.join(folder_path, 'train_images.npy')
        data = np.load(file_path)
        for j in range(0,10):
            axs[i, j].imshow(data[j].reshape(28,28), cmap='gray')
            axs[i, j].axis('off')
plt.tight_layout()
plt.show()

saída
Insira a descrição da imagem aqui

treinamento de método de ajuste fino

Suponha que comecemos a testar o modelo treinado do minist em ./model.h5. Precisamos carregar o modelo e depois testá-lo para continuar treinando os dados do minist-c.

#%%

import os
import numpy as np
import tensorflow.keras as layers
import tensorflow as tf
import datetime

TARGET_MODEL_DIR="./"
MODEL_NAME="model.h5"
epochs_count=5
"""
   jupyter打印的日志太大导致ipynb打开很慢,这里写个一模一样代码的py运行
"""
def againTrain(x_train, y_train, x_test, y_test):
    targetModel=os.path.join(TARGET_MODEL_DIR,MODEL_NAME)
    #记载CNN模型
    model=tf.keras.models.load_model(targetModel)
    """
    在使用Fine-tuning方法微调预训练模型时,通常会冻结模型的前几层,只调整模型的后面几层,这是因为:
    1.预训练模型的前几层通常是针对原始数据集的通用特征提取器,这些特征对于不同的任务和数据集都是有用的,因此我们可以直接保留这些特征提取器,不需要进行微调。
    2.预训练模型的后几层通常是针对特定任务进行的微调,这些层的参数需要根据具体任务和数据集进行调整,以使模型更好地适应特定的任务和数据集。
    3.如果我们将整个模型的所有层都进行微调,会导致训练时间较长,而且可能会出现过拟合等问题。因此,冻结前几层可以有效地减少训练时间,并提高模型的泛化能力。
    总之,冻结模型的前几层可以节省计算资源和训练时间,同时还可以提高模型的泛化能力,使其更好地适应新的任务和数据集。
    """
    model.layers[0].trainable = False
    model.layers[1].trainable = False
    # 对输入图像进行预处理
    x_train = x_train.reshape(-1, 28, 28, 1)
    x_train = x_train.astype('float32') / 255.0
    x_test = x_test.reshape(-1, 28, 28, 1)
    x_test = x_test.astype('float32') / 255.0
    y_train = tf.keras.utils.to_categorical(y_train, num_classes=10)
    y_test = tf.keras.utils.to_categorical(y_test, num_classes=10)
    now = datetime.datetime.now()  # 获取当前时间
    format_time = now.strftime("%Y-%m-%d%H-%M-%S")  # 转换为指定格式
    checkpoint = tf.keras.callbacks.ModelCheckpoint(targetModel, save_best_only=True, save_weights_only=False, monitor='val_loss')
    # 继续训练模型
    history = model.fit(x_train, y_train, batch_size=128, epochs=epochs_count, validation_data=(x_test, y_test),
                        callbacks=[checkpoint])
    test_loss, test_acc = model.evaluate(x_test, y_test)
    print('Test accuracy:', test_acc)
"""
  传入mnist-c,数据会非常大加载数据很慢,这里每加载一份子目录就训练一次,节省内存开销。
"""
def loadDataMnistC(data_root,func):
    dirlist=os.listdir(data_root)
    for i, folder_name in enumerate(dirlist):
        folder_path = os.path.join(data_root, folder_name)
        if os.path.isdir(folder_path):
            print("开始读取:"+folder_path)
            train_images = np.load(os.path.join(folder_path, 'train_images.npy'))
            train_labels = np.load(os.path.join(folder_path, 'train_labels.npy'))
            test_images = np.load(os.path.join(folder_path, 'test_images.npy'))
            test_labels = np.load(os.path.join(folder_path, 'test_labels.npy'))
            print("开始训练:"+folder_path)
            func(train_images,train_labels,test_images,test_labels)
            print("训练完成:"+folder_path)
# 加载 MNIST-C 数据集
data_root = './mnist_c'
model=None;
loadDataMnistC(data_root,againTrain)
print("全部训练完成")

Aqui, um determinado tipo é lido uma vez a cada vez e, em seguida, o modelo é gravado de volta na subpasta para treinamento. O modelo final é obtido até que o treinamento seja concluído.

Acho que você gosta

Origin blog.csdn.net/liaomin416100569/article/details/130597944
Recomendado
Clasificación