Los programadores de Dark Horse lo llevan a aprender las notas de estudio del marco TensorFlow de aprendizaje profundo de Python en 3 días

Directorio de artículos

Este es un programador de caballos oscuros que lo lleva a aprender las notas de estudio del marco TensorFlow de aprendizaje profundo de Python en 3 días

Enlace de video: Dark Horse Programmer lo lleva a jugar el marco TensorFlow de aprendizaje profundo de Python en 3 días

1. Introducción al aprendizaje profundo

1.1 La diferencia entre aprendizaje profundo y aprendizaje automático

Objetivo de aprendizaje: conocer la diferencia entre el aprendizaje profundo y el aprendizaje automático Diferencia
: el aprendizaje profundo no tiene extracción de características
inserte la descripción de la imagen aquí

aspecto característico

  1. El paso de ingeniería de características del aprendizaje automático se realiza manualmente y requiere mucha experiencia en el dominio.
  2. El aprendizaje profundo generalmente consta de múltiples capas, que a menudo combinan modelos más simples, pasando datos de una capa a otra para construir modelos más complejos. El modelo se obtiene automáticamente entrenando una gran cantidad de datos, sin necesidad de extracción manual de características

Los algoritmos de aprendizaje profundo intentan aprender características de alto nivel de los datos , que es una parte única del aprendizaje profundo. Así, se reduce la tarea de desarrollar un nuevo extractor de características para cada problema. Adecuado para campos de procesamiento de imágenes, voz y lenguaje natural en los que es difícil extraer características

Requisitos de volumen de datos y rendimiento computacional

El tiempo de ejecución que requiere el aprendizaje automático es mucho menor que el del aprendizaje profundo. Los parámetros del aprendizaje profundo suelen ser muy grandes y es necesario entrenar los parámetros a través de múltiples optimizaciones de una gran cantidad de datos.

inserte la descripción de la imagen aquí

  1. El aprendizaje profundo requiere grandes conjuntos de datos de entrenamiento
  2. Entrenar redes neuronales profundas requiere mucha potencia informática
  3. Puede llevar días, o incluso semanas, entrenar una red profunda utilizando un conjunto de datos de millones de imágenes. Por lo tanto, el aprendizaje profundo generalmente requiere un servidor de GPU potente para la informática.

representante del algoritmo

  1. Aprendizaje automático: Naive Bayes, árboles de decisión
  2. Aprendizaje profundo: redes neuronales

1.2 Escenarios de aplicación del aprendizaje profundo

  1. Reconocimiento de imágenes: reconocimiento de objetos, reconocimiento de escenas, reconocimiento de modelos de automóviles, detección y seguimiento de rostros, posicionamiento de puntos clave de rostros, autenticación de identidad de rostros
  2. Tecnología de procesamiento de lenguaje natural: traducción automática, reconocimiento de texto, diálogo de chat
  3. Tecnología del habla: reconocimiento de voz

1.3 Introducción al marco de aprendizaje profundo

Comparación de marcos comunes de aprendizaje profundo
inserte la descripción de la imagen aquí

  1. Los marcos más utilizados son TensorFlow y Pytorch, seguidos de Caffe y Caffe2.
  2. PyTorch y Torch son más adecuados para la investigación académica (investigación); TensorFlow, Caffe, Caffe2 son más adecuados para el despliegue en entornos de producción industrial (producción industrial)
  3. Caffe es bueno para gráficos estáticos; Torch y PyTorch son mejores para gráficos dinámicos; TensorFlow es útil en ambos casos.
  4. Tensorflow y Caffe2 están disponibles en dispositivos móviles.

instalación de tensorflow

Sitio web oficial: https://www.tensorflow.org/

CPU versión
2 GPU versión : más núcleos, más adecuada para procesar tareas paralelas

pip install tensorflow==1.8 -i https://pypi.douban.com/simple

#对于 1.15 及更早版本,CPU 和 GPU 软件包是分开的:
pip install tensorflow==1.15      # CPU
pip install tensorflow-gpu==1.15  # GPU

CPU: la cantidad de núcleos es pequeña;
la velocidad de cada núcleo es más rápida y el rendimiento es más fuerte; es más adecuado para procesar tareas secuenciales.

GPU: la cantidad de núcleos es grande,
pero la velocidad de procesamiento de cada núcleo es más lenta, es más adecuado para tareas paralelas.

Características de Tensorflow

  • Altamente flexible (flexibilidad profunda)
    • Se puede usar no solo para la investigación de algoritmos de redes neuronales, sino también para algoritmos comunes de aprendizaje automático, e incluso se puede usar TensorFlow siempre que el cálculo se exprese como un gráfico de flujo de datos.
  • Diversidad de idiomas (opciones de idioma)
    • TensorFlow está implementado en C++ y empaquetado en Python. Google pide a la comunidad que desarrolle más interfaces de idiomas a través de SwIG para admitir TensorFlow.
  • soporte de dispositivo
    • TensorFlow puede ejecutarse en una variedad de hardware. Al mismo tiempo, de acuerdo con las necesidades informáticas, puede asignar operaciones razonablemente a los dispositivos correspondientes. Por ejemplo, la convolución se asigna a GPU. También permite la distribución informática en CPU y GPU, y incluso admite el uso de gRPC para el procesamiento horizontal.
  • TensorboardVisualización
    • TensorBoard es un conjunto de aplicaciones web para TensorFlow, que se utiliza para monitorear el proceso en ejecución de TensorFlow o visualizar el gráfico de computación. TensorBoard actualmente admite 5 visualizaciones: escalares, imágenes, audio, histogramas y gráfico de computación. El panel de eventos de TensorBoard se puede usar para monitorear continuamente los indicadores clave en tiempo de ejecución, como la pérdida, la tasa de aprendizaje (tasa de aprendizaje) o la precisión en el conjunto de validación (precisión)

2, Flujo de tensor

2.1 TensorFlow inicial

Sitio web oficial: https://www.tensorflow.org/

Los programas de TensorFlow generalmente se organizan en una fase de diagrama de componentes y una fase de diagrama de ejecución.

  1. En la fase de construcción del gráfico, los pasos de ejecución de datos y operaciones se describen como un gráfico
  2. En la fase de ejecución del gráfico, use la sesión (recursos del sistema de llamadas) para ejecutar las operaciones en el gráfico construido
  • Figura: Esta es una representación del cálculo de TensorFlow como una dependencia entre instrucciones (datos + operación)
  • Sesiones: el mecanismo de TensorFlow para ejecutar gráficos de flujo de datos en uno o más dispositivos locales o remotos
  • tensor (datos): el objeto de datos básico en TensorFlow
  • Nodo (operación): Proporciona la operación W realizada en el gráfico
import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 去警告

def tensorflow_demo1():
   """
   tensoflow的基本结构
   """
   # python版本
   a=2
   b=3
   c=a+b
   print('python版本的加法操作:\n',c)

   # tensorflow实现加法操作
   a_t=tf.constant(2) # 定义常量
   b_t=tf.constant(3)
   c_t=a_t+b_t
   print('tensorflow版本的加法操作:\n',c_t)

   # 开启会话
   with tf.Session() as sess:
      c_t_value=sess.run(c_t)
      print('开启会话的结果\n',c_t_value)


if __name__ == '__main__':
   tensorflow_demo1()
'''
python版本的加法操作:
 5
tensorflow版本的加法操作:
 Tensor("add:0", shape=(), dtype=int32)
开启会话的结果
 5
'''    

2.2, figura

El gráfico contiene datos que fluyen entre un conjunto de objetos de unidades informáticas representados por tf.Operation y unidades informáticas representadas por tf.Tensor

Un gráfico, un espacio de nombres, sin interferir entre sí

  1. mapa predeterminado
  2. diagrama personalizado

Por lo general, tensorflow nos ayudará a crear una imagen de forma predeterminada

Dos formas de ver el gráfico predeterminado:

  • Se accede llamando a **tf.get_default_graph()**
  • Acceso a través de la propiedad del gráfico
def graph_demo():
   # tensorflow实现加法操作
   a_t = tf.constant(2)  # 定义常量
   b_t = tf.constant(3)
   c_t = a_t + b_t
   #查看默认图
   #方法1:调用方法
   defalut_g=tf.get_default_graph()
   print('默认图:',defalut_g)
   #方法2:调用属性
   print('a_t的图属性: ',a_t.graph)
   print('c_t的图属性: ',c_t.graph)
   # 开启会话
   with tf.Session() as sess:
      c_t_value = sess.run(c_t)
      print('sess的图属性:',sess.graph)
if __name__ == '__main__':
   graph_demo()
'''
默认图: <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
a_t的图属性:  <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
c_t的图属性:  <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
sess的图属性: <tensorflow.python.framework.ops.Graph object at 0x0000026249C36E48>
'''    

diagrama personalizado

  1. Personaliza el gráfico a través de tf.Graph()
  2. Defina tensores y nodos a través del administrador de contexto de gráfico tf.Graph.as_default() , y el administrador de contexto de gráfico vinculará automáticamente los tensores y nodos en el gráfico
  3. Para iniciar una sesión, debe pasar un mapa personalizado
def create_graph():
   # 自定义图
   new_graph=tf.Graph()
   # 图上下文管理器定义数据和操作
   with new_graph.as_default():
      a_new = tf.constant(20)
      b_new = tf.constant(30)
      c_new = a_new + b_new
      print("c_new:", c_new)
      print("a_new的图属性:", a_new.graph)
      print("c_new的图属性:", c_new.graph)
   #开启会话,执行图,注意这里需要传入自定义图对象graph
   with tf.Session(graph = new_graph) as sess:
      c_new_value=sess.run(c_new)
      print('自定义图的运算结果:',c_new_value)
      print('sess的图属性:',sess.graph)


if __name__ == '__main__':
   create_graph()
'''
c_new: Tensor("add:0", shape=(), dtype=int32)
a_new的图属性: <tensorflow.python.framework.ops.Graph object at 0x000001D3439BF278>
c_new的图属性: <tensorflow.python.framework.ops.Graph object at 0x000001D3439BF278>
自定义图的运算结果: 50
sess的图属性: <tensorflow.python.framework.ops.Graph object at 0x000001D3439BF278>
'''

TensorBoardVisualizer

Tensorflow se puede usar para los cálculos necesarios para entrenar redes neuronales profundas a gran escala, y los cálculos diseñados con esta herramienta suelen ser complejos y esotéricos. Para facilitar la comprensión, depuración y optimización de los programas de tensorflow, tensorflow proporciona la herramienta de visualización TensorBoard

Realizar el proceso de visualización del programa:

  1. Serializar los datos del gráfico como un archivo de eventos
  2. Abra la terminal e inicie tensorBoard

1. Serialice los datos del gráfico en un archivo de eventos

TensorBoard se ejecuta leyendo los archivos de eventos de TensorFlow, por lo que debe serializar el gráfico en un objeto Resumen

tf.summary.FileWriter(ruta, gráfico=sesión.gráfico)

2. Abra la terminal e inicie tensorBoard

tensorboard --logdir=ruta

def graph_demo():
	# tensorflow实现加法操作
	a_t = tf.constant(2)  # 定义常量
	b_t = tf.constant(3)
	c_t = a_t + b_t
    # 开启会话
	with tf.Session() as sess:
		c_t_value = sess.run(c_t)
		print('sess的图属性:',sess.graph)

	# sess图序列化为summary对象
	# 参数一:输出sumary对象的路径,参数二:需要进行序列化的图
	tf.summary.FileWriter('./temp/summary',graph = sess.graph)
    
if __name__ == '__main__':
    graph_demo()

inserte la descripción de la imagen aquí

Entra en la terminal, presta atención al camino

tensorboard --logdir='./machine_learning/temp/summary'

inserte la descripción de la imagen aquí

Haga clic en http://MSI:6006 para ir a la página de tensorBoard

inserte la descripción de la imagen aquí

Operación de objeto de operación OP

tipo ejemplo
operación escalar agregar, sub, mul, div, exp, log, mayor, menor, igual
operación vectorial concat,slice,slot, constante,rank,shape, shuffle
Operaciones Matriciales matmul, matrizinversa,matrizfechaminante
operaciones con el estado Variable, asignar, asignar agregar
componentes de la red neuronal softmax, sigmoid, relu, convolución, max_pool
almacenar, restaurar Guardar, restaurar
Operaciones sincrónicas y en cola Poner en cola, Quitar de la cola, MutexAcquire, MutexRelease
flujo de control Fusionar, Cambiar, Entrar, Salir, Siguiente lteración
función de operación objeto de operación
tf.constant (objeto tensor) Objeto Tensor de entrada-Objeto Tensor de salida constante
tf.add(objeto tensor 1, objeto tensor 2) Entrada (objeto Tensor 1, objeto Tensor 2), añadir objeto, salida objeto Tensor 3

Un objeto de operación (Operación) es un nodo en el gráfico TensorFlow, que puede recibir 0 o más objetos Tensor de entrada y puede generar 0 o más objetos Tensor. El objeto Operation se pasa a través del constructor op (como tf.matmul() ) creado.

Por ejemplo: c = tf.matmul(a, b) crea un objeto Operation, el tipo es de tipo MatMul, toma los tensores a, b como entrada, c como salida y genera datos, que también son datos impresos al imprimir. Entre ellos, tf.matmul) es una función, y se creará un objeto correspondiente a través de la clase MatMul durante la ejecución de la función matmul

Tenga en cuenta que se imprime el valor del tensor, que puede entenderse como el valor incluido en el OP. Y cada instrucción OP corresponde a un nombre único, como la Const:0 anterior, que también se puede mostrar en TensorBoard

Tenga en cuenta que un objeto tf.Tensor se nombra explícitamente después de la tf.Operation que genera ese tensor. Un nombre de tensor tiene la forma "<NOMBRE_OP>:<i>", donde:
"<NOMBRE_OP>" es el nombre de la instrucción que produjo el tensor
. "<i>" es un número entero que indica que el tensor fue creado en la instrucción El índice en la salida de

nombre de comando

Un gráfico tiene su propio espacio de nombres.

Un objeto tf.Graph define un espacio de nombres para los objetos tf.Operation que contiene. TensorFlow elige automáticamente un nombre único para cada instrucción en el gráfico, o el usuario puede especificar un nombre descriptivo para que el programa sea más fácil de leer. Podemos reescribir el nombre de la directiva de la siguiente manera

  • Cada función API que crea un nuevo tf.Operation o devuelve un nuevo tf.Tensor puede aceptar un parámetro de nombre opcional.

Por ejemplo, tf.constant(42.0, name="answer") crea un nuevo tf.Operation llamado "answer" y devuelve un tf.Tensor llamado "answer:0" . Si el gráfico predeterminado ya contiene una directiva denominada "respuesta", TensorFlow agrega "1", "2", etc. al nombre para que sea único.

  • Cuando se complete la modificación, el nombre que mostramos en Tensorboard también se modificará

2.3 Sesión

creación de sesión

  • **tf.Session: ** utilizado en el programa completo
  • tf.InteractiveSession : para TensorFlow en un contexto interactivo, como el shell

1 TensorFlow usa la clase tf.Session para representar la conexión entre un programa cliente (generalmente un programa de Python, pero hay disponibles interfaces similares para otros lenguajes) y el tiempo de ejecución de C++

2 Un objeto tf.Session brinda acceso a dispositivos en la computadora local y a dispositivos remotos mediante el tiempo de ejecución distribuido de TensorFlow.

Para ver rápidamente el valor de un tensor, llame a object.eval() en la sesión para ver

inserte la descripción de la imagen aquí

administrador de contexto de sesión

Recursos que una sesión puede poseer, como tf.Variable, tf.QueueBase y tf.ReaderBase. Es importante liberar estos recursos cuando ya no se necesitan. Por lo tanto, debe llamar al método tf.Session.close en la sesión o usar la sesión como administrador de contexto.

tf.Session(objetivo='',gráfico=Ninguno,config=Ninguno)

  1. destino: si deja este parámetro en blanco (el valor predeterminado), la sesión solo usará dispositivos de la computadora local. Se puede especificar una URL grpc:// para especificar la dirección de un servidor TensorFlow, lo que hace que la sesión sea accesible para todos los dispositivos en la computadora controlada por ese servidor.
  2. gráfico: de forma predeterminada, una nueva tf.Session se vinculará al gráfico predeterminado actual
  3. config: este parámetro le permite especificar un tf.ConfigProto para controlar el comportamiento de la sesión. Por ejemplo, el protocolo ConfigProto se usa para imprimir información de uso del dispositivo
# 开启会话上下文管理器(推荐)
with tf.Session() as sess:
	sess.run(sth)

# 传统的会话定义
sess=tf.Session()
sum_t=sess.run(c_t)
sess.close()

# 运行会话并打印设备信息
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True))

ejecución de sesión ()

ejecutar (busca, feed_dict=Ninguno, opciones=Ninguno, run_metadata=Ninguno)

  • Ejecute la operación usando sess.run()
  • recupera : pasa en una sola operación, o lista, tupla (perteneciente al tipo tensorflow)
  • feed_dict : el parámetro ejecuta el valor del tensor en el gráfico de cobertura de la persona que llama y lo asigna en tiempo de ejecución. Cuando se usa con marcadores de posición **tf.placeholder()**, comprobará si la forma del valor es compatible con los marcadores de posición.

Nota: la operación también se puede ejecutar usando tf.operation.eval(), pero debe ejecutarse en una sesión

# 创建图
a = tf.constant(5.0)
b = tf.constant(6.0)
c = a + b

# 创建会话
sess = tf.Session()

# 计算C的值
print(sess.run(c))
print(c.eval(session=sess))

operación feed_dict()

Preste atención al error de error informado en tiempo de ejecución:

RuntimeError: si la sesión está en un estado no válido (por ejemplo, cerrado).

TypeError: si las claves fetch o feed_dict son de tipo inapropiado.

valueError: si la clave fetch o feed_dict no es válida o hace referencia a una clave que no existe en el tensor.

  • El marcador de posición proporciona un marcador de posición y los parámetros se pasan a través de feed_dict en tiempo de ejecución.
def feed_dict_demo():
	# 当不确定值的时候,通过placeholder占位符解决
	a=tf.placeholder(tf.float32)
	b=tf.placeholder(tf.float32)
	c=tf.add(a,b)

	#开启会话,打印设备
	with tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_placement=True)) as sess:
		c_value=sess.run([a,b,c],feed_dict={
    
    a:3.2,b:2.3})
		print('c_value: ',c_value)

if __name__ == '__main__':
	feed_dict_demo()
'''
Device mapping: no known devices.
Add: (Add): /job:localhost/replica:0/task:0/device:CPU:0
Placeholder_1: (Placeholder): /job:localhost/replica:0/task:0/device:CPU:0
Placeholder: (Placeholder): /job:localhost/replica:0/task:0/device:CPU:0
c_value:  [array(3.2, dtype=float32), array(2.3, dtype=float32), 5.5]
'''

2.4, tensor

2.4.1 Definición

El tensor de TensorFlow es una matriz N-dimensional de tipo tf.Tensor.

escalar: un número ---- tensor de orden 0

Vector: matriz unidimensional ----- tensor de orden 1

Matriz: matriz bidimensional ------ tensor de segundo orden

Tensor de rango 3

  • tipo: tipo de datos
  • Cuando no se especifica ningún tipo, el tipo predeterminado es:
    • Entero: tf.int32
    • Tipo de punto flotante: tf.float32
  • forma: forma (orden)

tipo de tensor

tipo de datos tipo pitón describir
DT_FLOAT tf.float32 flotante de 32 bits.
DT_DOBLE tf.float64 flotante de 64 bits.
DT_INT64 t.f. int64 Entero con signo de 64 bits.
DT_INT32 t.f. int32 Entero con signo de 32 bits.
DT_INT16 tf.int16 Entero con signo de 16 bits.
DT_INT8 tf.int8 Entero con signo de 8 bits.
DT_UINT8 tf.uint8 Entero sin signo de 8 bits.
DT_STRING tf.cadena Matriz de bytes de longitud variable Cada elemento tensor es una matriz de bytes.
DT_BOOL tf.bool booleano.
DT_COMPLEX64 tf.complex64 Un número complejo que consta de dos números de coma flotante de 32 bits: un número real y un número imaginario.
DT_QINT32 tf.qint32 Entero con signo de 32 bits utilizado para operaciones cuantificadas.
DT_QINT8 tf.qint8 Int de 8 bits utilizado para cuantificar Ops.
DT_QUINT8 tf.quint8 Entero sin signo de 8 bits para operaciones máximas

orden de tensor

orden ejemplo de matemáticas Pitón ejemplo
0 indicador (solo tamaño) s = 483
1 vector (tamaño y orientación) v = [1.1,2.2,3.3]
2 matriz (ficha de datos) metro = [[1,2,3],[4,5,6],[7,8,9]]
3 Tensor de rango 3 (Estéreo de datos) t = [[[2],[4],[6]],[[8],[10],[12]],[[14],[16],[18]]]
norte n orden (piensa por ti mismo)
def tensor_demo():
    """
    张量的演示
    """
    tensor1 = tf.constant(4.0)
    tensor2 = tf.constant([1,2,3,4])  # 未指定类型,默认类型
    linear_squares = tf.constant([[4],[9],[16],[25]],dtype=tf.int32)
    print("tensor1:", tensor1)
    print("tensor2:", tensor2)
    print("linear_square:", linear_squares)
    return None


if __name__ == "__main__":
    tensor_demo()
'''
tensor1: Tensor("Const:0", shape=(), dtype=float32)
tensor2: Tensor("Const_1:0", shape=(4,), dtype=int32)
linear_square: Tensor("Const_2:0", shape=(4, 1), dtype=int32)
'''

2.4.2 Creando tensores

Crear un tensor de valor fijo

tf.zeros(forma, dtype=tf.float32,name=Ninguno)

Cree un tensor con todos los elementos establecidos en cero. Esta operación devuelve un tensor de tipo dtype con forma de forma y todos los elementos establecidos en cero.

tf.zeros_like(tensor,dtype=Ninguno, nombre=Ninguno)

Ordene Tensor() para tensor, esta operación devuelve un tensor del mismo tipo y forma que tensor con todos los elementos establecidos en cero.

tf.ones(forma, dtype=tf.float32, nombre=Ninguno)

Cree un tensor con todos los elementos establecidos en 1. Esta operación devuelve un Tensor de tipo, con forma de tipo dtipo y todos los elementos establecidos en 1.

tf.ones_like(tensor, dtype=Ninguno, nombre=Ninguno)

Ordene Tensor() para tensor, esta operación devuelve un tensor del mismo tipo y forma que tensor con todos los elementos establecidos en 1.

tf.fill(dims, value, name=None)

创建一个填充了标量值的张量。此操作创建一个张量的形状dims并填充它value.

tf.constant(value, dtype=None,shape=None, name=‘Const’"

创建一个常数张量。

创建随机张量

一般我们经常使用的随机数函数Math.randoml()产生的是服从均匀分布的随机数,能够模拟等概率出现的情况,例如扔一个骰子,1到6点的概率应该相等,但现实生活中更多的随机现象是符合正态分布的,例如20岁成年人的体重分布等。

假如我们在制作一个游戏,要随机设定许许多多NPC的身高,如果还用Math.random),生成从140到220之间的数字,就会发现每个身高段的人数是一样多的,这是比较无趣的,这样的世界也与我们习惯不同,现实应该是特别高和特别矮的都很少,处于中间的人数最多,这就要求随机函数符合正态分布。

tf.truncated_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32,seed=None,name=None)

从截断的正态分布中输出随机值,和 tf.random_normal(0一样,但是所有数字都不超过两个标准差

tf.random_normal(shape, mean=0.0,stddev=1.0, dtype=tf.float32, seed=None, name=None)

从正态分布中输出随机值,由随机正态分布的数字组成的矩阵

其它特殊的创建张量的OP

  • tf.Variable

  • tf.placeholder

inserte la descripción de la imagen aquí

2.4.3、张量的变换

1 类型改变

  • tf.string_to_number(string_tensor, out_type=None, name=None)
  • tf.to_double(x, name=‘ToDouble’)
  • tf.to_float(x, name=‘ToFloat’)
  • tf.to_bfloat16(x, name=“ToBFloat16”)
  • tf.to_int32(x, name=‘Tolnt32’)
  • tf.to_int64(x, name=‘Tolnt64’)
  • tf.cast(x, dtype, name=None),通用类型转换
def cast_demo():
   a=tf.constant(4.0)
   b=tf.cast(a,dtype = tf.float64)
   print(a)
   print(b)

if __name__ == '__main__':
   cast_demo()
'''
Tensor("Const:0", shape=(), dtype=float32)
Tensor("Cast:0", shape=(), dtype=float64)
'''

2 形状改变
tensorflow的张量具有两种形状变换,动态形状静态形状

  1. tf.reshape(tensor,shape):动态创建新张量,当原形状固定的时候,动态改变张量的时候,张量的元素个数必须一致。如shape(2,3) 元素个数为6,则动态改变张量的时候,也要确保元素的个数为6
  2. tensor.set_shape(shape):改变静态形状

静态形状:初始创建张量时的形状

什么情况下可以改变静态形状:

只有在形状还没有完全固定下来的情况下,如shape(?,?);转换形状的时候,只能一维到一维,二维到二维,而不能跨维度改变形状,如 shape=[None, 10],前面无所谓变化,但后面一个必须要10

def shape_demo():
   a = tf.constant(4.0)
   b = tf.placeholder(dtype=tf.float32, shape=[None, 10])
   print('a:',a)
   print('b:',b)

   b.set_shape((2,10))
   print('修改b静态形状',b)
   c_dynamic=tf.reshape(b,shape = (10,2))
   # c_dynamic=tf.reshape(b,shape = (10,10)) 报错
   print('修改b动态形状',c_dynamic)

if __name__ == '__main__':
   shape_demo()
'''
a: Tensor("Const:0", shape=(), dtype=float32)
b: Tensor("Placeholder:0", shape=(?, 10), dtype=float32)
修改b静态形状 Tensor("Placeholder:0", shape=(2, 10), dtype=float32)
修改b动态形状 Tensor("Reshape:0", shape=(10, 2), dtype=float32)
'''

张量的数学运算,自己去查api

  • 算术运算符(如tf.add())
  • 基本数学函数
  • 矩阵运算(如tf.matmul())
  • reduce操作(如tf.reduce_sum()、tf.reduce_mean()
  • 序列索引操作

2.5、变量OP

TensorFlow变量是表示程序处理的共享持久状态的最佳方法。变量通过tf.Variable类进行操作。

变量的特点:

  • 存储持久化,如变量存储模型参数
  • 可修改值
  • 可指定被训练

2.5.1 创建变量

tf.Variable(initia_value=None, trainable=True, collections=None, name=None)

  1. initial_value:初始化的值
  2. trainable:是否被训练
  3. collections:新变量将添加到列出的图的集合中collections,默认为[GraphKeys.GLOBAL_VARIABLES],如果trainable是True变量也被添加到图形集合GraphKeys.TRAINABLE_VARIABLES

注意:创建完变量后,需要进行变量初始化,且运行该初始化后,才能使用变量

init = tf.global_variables_initializer()

sess.run(init)

def variable_demo():
	#创建变量
	a=tf.Variable(initial_value = 30)
	b=tf.Variable(initial_value = 50)
	c=tf.add(a,b)
	print('a:',a)
	print('b:',b)
	print('c:',c)
	# 变量初始化
	init=tf.global_variables_initializer()

	#开启会话
	with tf.Session() as sess:
		sess.run(init) # 运行初始化
		a_value,b_value,c_value=sess.run([a,b,c])
		print('a_value,',a_value)
		print('b_value,',b_value)
		print('c_value,',c_value)

if __name__ == '__main__':
	variable_demo()
'''
a: <tf.Variable 'Variable:0' shape=() dtype=int32_ref>
b: <tf.Variable 'Variable_1:0' shape=() dtype=int32_ref>
c: Tensor("Add:0", shape=(), dtype=int32)
a_value, 30
b_value, 50
c_value, 80
'''

2.5.2、修改变量的命名空间

tf.variable_scope()

  1. 会在OP变量的名字前面添加新的命名空间名
  2. 命名空间会使图的结构更加清晰
def scope_demo():
   with tf.variable_scope('myscore'):
      a = tf.Variable(initial_value = 30)
      b = tf.Variable(initial_value = 50)
   with tf.variable_scope('yourscore'):
      c = tf.add(a, b)
   print('a:', a)
   print('b:', b)
   print('c:', c)

if __name__ == '__main__':
   scope_demo()
'''
a: <tf.Variable 'myscore/Variable:0' shape=() dtype=int32_ref>
b: <tf.Variable 'myscore/Variable_1:0' shape=() dtype=int32_ref>
c: Tensor("yourscore/Add:0", shape=(), dtype=int32)
'''

2.6、高级API

2.6.1、其他基础API

1、tf.app
这个模块相当于为TensorFlow进行的脚本提供一个main函数入口,可以定义脚本运行的flags

2、tf.image
TensorFlow的图像处理操作。主要是一些颜色变换、变形和图像的编码和解码

3、tf.gfile
这个模块提供了一组文件操作函数

4、tf.summary
用来生成TensorBoard可用的统计日志,目前Summary主要提供了4种类型:
audio、image、histogram、scalar

5、tf.python_io
用来读写TFRecords文件

6、tf.train
这个模块提供了一些训练器,与tf.nn结合起来,实现一些网络的优化计算

7、tf.nn
这个模块提供了一些构建神经网络的底层函数。TensorFlow构建网络的核心模块,其中包含了添加各种层的函数,比如添加卷积层、池化层等。

2.6.2、高级API

1、tf.keras
Kears本来是一个独立的深度学习库,tensorflow将其学习过来,增加这部分模块在于快速构建模型

2、tf.layers
高级API,以便高级的概念层来定义一个模型。类似tf.kears

3、tf.contrib
tf.contrib.layers提供够将计算图中的网络层、正则化、摘要操作,是构建计算图的高级操作,但是tf.contrib包含不稳定和实验代码,有可能以后API会改变

4、tf.estimator
一个estimator相当于model + training + evaluate 的合体。在模块中,已经实现了几种简单的分类器和回归其,包括:Baseline,learning 和 DNN。这里的DNN的网络,只是全连接网络,没有提供卷积之类的

关于tensorflow的API展示

inserte la descripción de la imagen aquí

2.7、案例:实现线性回归

回顾:根据数据建立回归模型,w1x1+w2x2+…+b = y,通过真实值与预测值之间建立误差,使用梯度下降优化得到损失最小对应的权重和偏置。最终确定模型的权重和偏置参数。最后可以用这些参数进行预测。

  1. 构建线性回归模型
  2. 构造损失函数(均方误差)
  3. 优化损失(梯度下降)

使用到的API

运算:

  • 矩阵运算:tf.matmul(x,w)
  • 平方:tf.square(error)
  • 均方:tf.reduce_mean(error)

梯度下降优化:

tf.train.GradientDescentOptimizer(learning_rate)

  • 梯度下降优化

  • learning_rate:学习率,一般为0~1之间比较小的值

  • method:

    • minimize(loss) 最小化
  • return:梯度下降op

分析

1)准备真实数据:

tf.random_normal()

x:特征值,形状:(100,1),随机指定100个点,只有一个特征值
y_true:目标值,形状:(100,1)
y_true = 0.8x + 0.7 ,100个样本
即假设x和y之间的关系满足: y =kx + b, 最后求出k≈0.8,b=0.7 为正确的答案

即y_predict=x*weights+bias

2)构建模型

y_predict = tf.matmul(x, weights) + bias

3)构造损失函数(均方误差)

error = tf.reduce_mean(tf.square(y_predict - y_true))

4)优化损失:梯度下降优化器

optimizer = tf.train.GrandientDescentOptimizer(learning_rate=0.01).minimize(error)

def linear_regression():
	# 1、准备数据
	X=tf.random_normal(shape=[100,1]) # 特征值 100行1列
	y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

	# 2、构建模型
	# 采用变量定义模型参数
	weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 权重
	bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 偏置
	y_predict=tf.matmul(X,weigths)+bias # 预测值

	# 3、构建损失函数(均方误差)
	error=tf.reduce_mean(tf.square(y_predict-y_true))

	# 4、优化损失函数
	optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

	# 初始化变量
	init=tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		sess.run(init) # 运行初始化
		# 查看没有训练之前,初始化模型参数值
		print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

		# 开始训练模型,迭代100次
		for i in range(100):
			sess.run(optimizer)
			print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))


if __name__ == '__main__':
	linear_regression()
'''
训练前模型参数为:权重-2.152965, 偏置-1.636178, 损失值14.106889 
第1次训练前模型参数为:权重-2.086562, 偏置-1.589710, 损失值15.449847 
第2次训练前模型参数为:权重-2.022885, 偏置-1.536769, 损失值12.712150 
第3次训练前模型参数为:权重-1.953819, 偏置-1.488234, 损失值11.221785 
.....
第98次训练前模型参数为:权重0.379509, 偏置0.383643, 损失值0.302479 
第99次训练前模型参数为:权重0.386806, 偏置0.389533, 损失值0.247333 
第100次训练前模型参数为:权重0.396212, 偏置0.395469, 损失值0.296869 
'''

学习率的设置、步数的设置与梯度爆炸

学习率越大,训练到较好结果的步数越小;学习率越小,训练到较好结果的步数越大。

但是学习过大会出现梯度爆炸现象。

  1. 在极情况下,权重的值变得非常大,以至于溢出,导致 NaN值
  2. 如当线性回归的学习率设置为100时候,迭代100次的时候就出现权重和偏置为NaN

如何解决梯度爆炸问题(深度神经网络当中更容易出现)

  1. 重新设计网络
  2. 调整学习率
  3. 使用梯度截断(在训练过程中检查和限制梯度的大小)
  4. 使用激活函数

2.8、其他功能

2.8.1、增加变量显示

目的:在TensorBoard当中观察模型的参数、损失值等变量值的变化

1、收集变量

  • tf.summary.scalar(name=",tensor) 收集对于损失函数和准确率等单值变量,name为收集变量的名字,tensor为对象
  • tf.summary.histogram(name=‘’,tensor) 收集高维度的变量参数
  • tf.summary.image(name=",tensor) 收集输入的图片张量能显示图片

2、合并变量写入事件文件

  • 创建事件文件 tf.summary.FileWriter('path, graph=sess.graph)

  • merged = tf.summary.merge_all() 合并变量

  • 运行合并: summary = sess.run(merged),每次迭代都需运行

  • 添加:FileWriter.add_summary(summary,i),i表示第几次的值

  1. 创建事件文件
  2. 收集变量
  3. 合并变量
  4. 运行合并变量
  5. 将迭代后的变量写入到事件文件中
def linear_regression():
	# 1、准备数据
	X=tf.random_normal(shape=[100,1]) # 特征值 100行1列
	y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

	# 2、构建模型
	# 采用变量定义模型参数
	weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 权重
	bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1])) # 偏置
	y_predict=tf.matmul(X,weigths)+bias # 预测值

	# 3、构建损失函数(均方误差)
	error=tf.reduce_mean(tf.square(y_predict-y_true))

	# 4、优化损失函数
	optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

	# 初始化变量
	init=tf.global_variables_initializer()

	# 收集变量
	tf.summary.scalar('error',error)
	tf.summary.histogram('weights',weigths)
	tf.summary.histogram('bias',bias)

	# 合并变量
	merged=tf.summary.merge_all()

	# 开启会话
	with tf.Session() as sess:
		sess.run(init) # 运行初始化
		# 查看没有训练之前,初始化模型参数值
		print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

		# 创建事件文件
		file_writer=tf.summary.FileWriter('./temp/linear/',graph = sess.graph)
		# 运行合并变量操作
		summary=sess.run(merged)

		# 开始训练模型,迭代100次
		for i in range(100):
			sess.run(optimizer)
			print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))

			# 将每次迭代后的合并变量写入到事件文件中
			file_writer.add_summary(summary,i)

if __name__ == '__main__':
	linear_regression()

在Terminal输入 tensorboard --logdir=‘./temp/linear’
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

2.8.2、增加命名空间

tf.variable_scope(name=‘’)

使得代码结构更加信息,TensorBoard图结构更加清楚

def linear_regression():
   # 1、准备数据
   with tf.variable_scope('prepare_data'):
      X=tf.random_normal(shape=[100,1],name='feature') # 特征值 100行1列
      y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

   # 2、构建模型
   # 采用变量定义模型参数
   with tf.variable_scope('create_model'):
      weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name = 'Weights') # 权重
      bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name='Bias') # 偏置
      y_predict=tf.matmul(X,weigths)+bias # 预测值

   # 3、构建损失函数(均方误差)
   with tf.variable_scope('loss_function'):
      error=tf.reduce_mean(tf.square(y_predict-y_true))

   # 4、优化损失函数
   with tf.variable_scope('optimizer'):
      optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

   # 初始化变量
   init=tf.global_variables_initializer()

   # 收集变量
   tf.summary.scalar('error',error)
   tf.summary.histogram('weights',weigths)
   tf.summary.histogram('bias',bias)

   # 合并变量
   merged=tf.summary.merge_all()

   # 开启会话
   with tf.Session() as sess:
      sess.run(init) # 运行初始化
      # 查看没有训练之前,初始化模型参数值
      print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

      # 创建事件文件
      file_writer=tf.summary.FileWriter('./temp/linear/',graph = sess.graph)
      # 运行合并变量操作
      summary=sess.run(merged)

      # 开始训练模型,迭代100次
      for i in range(100):
         sess.run(optimizer)
         print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))

         # 将每次迭代后的合并变量写入到事件文件中
         file_writer.add_summary(summary,i)

if __name__ == '__main__':
   linear_regression()

inserte la descripción de la imagen aquí

2.8.3、模型的保存与加载

tf.train.Saver(var_list=None,max_to_keep=5)

  • 保存和加载模型(保存文件格式: checkpoint文件)
  • var_list:指定将要保存和还原的变量。它可以作为一个dict或一个列表传递
  • max_to_keep:指示要保留的最近检查点文件的最大数量。创建新文件时,会删除较旧的文件。如果无或0,则保留所有检查点文件。默认为5(即保留最新的5个检查点文件。)

步骤:

注意:

1、path,目录一定要提前创建

2、保存的是会话(里面是具体模型的参数)

3、保存模型的格式为 ckpt

  1. 实例化Saver
  2. 保存:saver.save(sess, path)
  3. 加载:saver.restore(sess, path)
def linear_regression():
   # 1、准备数据
   with tf.variable_scope('prepare_data'):
      X=tf.random_normal(shape=[100,1],name='feature') # 特征值 100行1列
      y_true=tf.matmul(X,[[0.8]])+0.7 # 真实值 y_true = 0.8x + 0.7

   # 2、构建模型
   # 采用变量定义模型参数
   with tf.variable_scope('create_model'):
      weigths=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name = 'Weights') # 权重
      bias=tf.Variable(initial_value = tf.random_normal(shape = [1,1]),name='Bias') # 偏置
      y_predict=tf.matmul(X,weigths)+bias # 预测值

   # 3、构建损失函数(均方误差)
   with tf.variable_scope('loss_function'):
      error=tf.reduce_mean(tf.square(y_predict-y_true))

   # 4、优化损失函数
   with tf.variable_scope('optimizer'):
      optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(error)

   # 初始化变量
   init=tf.global_variables_initializer()

   # 收集变量
   tf.summary.scalar('error',error)
   tf.summary.histogram('weights',weigths)
   tf.summary.histogram('bias',bias)

   # 合并变量
   merged=tf.summary.merge_all()

   # 开启会话
   with tf.Session() as sess:
      sess.run(init) # 运行初始化
      # 查看没有训练之前,初始化模型参数值
      print('训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(weigths.eval(),bias.eval(),error.eval()))

      # 创建事件文件
      file_writer=tf.summary.FileWriter('./temp/linear/',graph = sess.graph)
      # 运行合并变量操作
      summary=sess.run(merged)

      # 实例化Saver
      saver=tf.train.Saver()

      # 开始训练模型,迭代100次
      # for i in range(100):
      #  sess.run(optimizer)
      #  print('第%d次训练前模型参数为:权重%f, 偏置%f, 损失值%f '%(i+1,weigths.eval(),bias.eval(),error.eval()))
      #
      #  # 将每次迭代后的合并变量写入到事件文件中
      #  file_writer.add_summary(summary,i)

         # 保存模型
         # if i%10==0:
         #  saver.save(sess,save_path = './temp/model/my_linear.ckpt')

         # 加载模型
      if os.path.exists('./temp/model/checkpoint'):
         saver.restore(sess, './temp/model/my_linear.ckpt')
         print('训练后模型参数为:权重%f, 偏置%f, 损失值%f ' % (weigths.eval(), bias.eval(), error.eval()))
        
if __name__ == '__main__':
	linear_regression()   
    
'''
训练前模型参数为:权重-1.358256, 偏置2.844705, 损失值6.984871 
训练后模型参数为:权重0.486487, 偏置0.413228, 损失值0.159787 
'''    

2.8.4、命令行参数设置

tf.app.flags(DEFINE),它支持应用从命令行接受参数,可以用来指定集群配置等。在tf.app.flags()下面有各种定义参数的类型

  • DEFINE_string(flag _name,default_value, docstring)
  • DEFINE_integer(flag_name, default_value, docstring)
  • DEFINE_boolean(flag_name, default_value, docstring)
  • DEFINE_float(flag_name, default_value, docstring)
  • tf.app.flags,在flags有一个FLAGS标志,它在程序中可以调用到我们前面具体定义的flag_name
  • 通过tf.app.run() 会自动启动 main(argv) 函数
#定义一些常用的命令行参数
#训练步数
tf.app.flags.DEFINE_integer("max_step",0,"训练模型的步数")
#定义模型的路径                            
tf.app.flags.DEFINE_string("model_dir", " ","模型保存的路径+模型名字")
#定义获取命令行参数
FLAGS = tf.app.flags.FLAGS                      

tf.app.flags(DEFINE) 使用

import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 去警告

# 1)定义命令行参数
tf.app.flags.DEFINE_integer("max_step", 100, "训练模型的步数")
tf.app.flags.DEFINE_string("model_dir", "Unknown", "模型保存的路径+模型的名字")
# 2)简化变量名
FLAGS = tf.app.flags.FLAGS

def command_demo():
    """
    命令行参数演示
    """
    print("max_step:", FLAGS.max_step)
    print("model_dir:", FLAGS.model_dir)

if __name__ == '__main__':
   command_demo()

'''
max_step: 100
model_dir: Unknown
'''

inserte la descripción de la imagen aquí

tf.app.run()使用

def main(argv):
   """
   这里是总文件,各种模块调用写在这里
   """
   print(argv)

if __name__ == '__main__':
   tf.app.run()
'''
['E:/RuanJian_2/PyCharm/PyCode/heima/junior/machine_learning/tensorflow_demo1.py']
'''

3、数据读取

3.1、文件读取流程

3.1.1、文件读取流程

inserte la descripción de la imagen aquí

shuffle 洗牌

第一阶段:构造文件名队列

第二阶段:读取与解码

第三阶段:批处理 (需要手动开启线程)

注意:这些操作需要启动运行这些队列操作的线程,以便我们在进行文件读取的过程中能够顺利进行入队出队操作

1、构造文件名队列
将需要读取的文件的文件名放入到文件名队列

tf.train.string_input_producer(string_tensor, shuffle=True)

  1. string_tensor:包含文件名+路径的1阶张量, 一般传入列表
  2. num_epochs:过几遍数据,默认无限过数据
  3. return:文件队列

2、读取与解码
从队列当中读取文件内容,并进行解码操作。

2.1、读取文件内容

阅读器默认每次只读取一个样本

具体来说:

文本文件默认一次读取一行,图片文件默认一次读取一张图片,二进制文件一次读取指定字节数(最好是一个样本的字节数),TFRecords默认一次读取一个example

  1. tf.TextLineReader: 读取文本
    • 阅读文本文件逗号分隔值(CSV)格式,默认按行读取
    • return:读取器实例
  2. tf.WholeFileReader: 用于读取图片文件
    • return:读取器实例
  3. tf.FixedLengthRecordReader(record_bytes) : 读取二进制文件
    • 要读取每个记录是固定数量字节的二进制文件
    • orecord_bytes:整型,指定每次读取(一个样本)的字节数
    • return:读取器实例

1、它们有共同的读取方法: read(file_queue),并且都会返回一个Tensors元组(key文件名字,value默认的内容(一个样本))

2、由于默认只会读取一个样本,所以如果想要进行批处理,需要使用tf.train.batch或tf.train.shuffle_batch进行批处理操作,便于之后指定每批次多个样本的训练。

即file_queue=tf.train.strng_input_produce(string_tensor, shuffle=True)

key,value=读取器.read(file_queue)

key: 文件名

value: 一个样本

2.2、内容解码

读取不同类型的文件,也应该对读取到的不同类型的内容进行相对应的解码操作,解码成统一的Tensor格式

  1. tf.decode_csv(): 解码文本文件内容·
  2. tf.image.decode_jpeg(contents即样本)
    • 将JPEG编码的图像解码为uint8张量
    • return :uint8张量,3-D形状[height, width, channels].
  3. tf.image.decode_png(contents即样本)
    • 将PNG编码的图像解码为uint8张量
    • return: 张量类型,3-D形状[height, width, channels]
  4. tf.decode_raw()︰解码二进制文件内容
    • 与tf.FixedLengthRecordReader搭配使用,二进制读取为uint8类型

解码阶段,默认所有的内容都解码成tf.uint8类型,如果之后需要转换成指定类型则可使用 tf.cast() 进行相应转换。

3 批处理

解码之后,可以直接获取默认的一个样本内容了,但如果想要获取多个样本,需要加入到新的队列进行批处理。

  1. tf.train.batch(tensors, batch_size, num_threads = 1, capacity = 32,name=None)

    • 读取指定大小(个数)的张量

    • tensors:可以是包含张量的列表,批处理的内容放到列表当中

    • batch_size:从队列中读取的批处理大小

    • num_threads:进入队列的线程数

    • capacity:整数,队列中元素的最大数量

    • return:tensors

  2. tf.train.shuffle_batch() : 随机批量操作

3.1.2、线程操作

以上用到的队列都是tf.train.QueueRunner对象。

每个QueueRunner都负责一个阶段,tf.train.start_queue_runners()函数会要求图中的每个QueueRunner启动它的运行队列操作的线程。(这些操作需要在会话中开启)

tf.train.start_queue_runners(sess=None, coord=None)

  • 收集图中所有的队列线程,默认同时启动线程
  • sess:所在的会话
  • coord:线程协调器
  • return:返回所有线程

tf.train.Coordinator()

  • 线程协调器,对线程进行管理和协调
  • request_stop():请求停止
  • should_stop():询问是否结束
  • join(threads=None, stop_grace_period_secs=120):回收线程
  • return:线程协调器实例

3.2、图片读取

3.2.1、图像基本知识

组成图片最基本单位是 像素

1、图片三要素
组成一张图片特征值是所有的像素值,有三个维度:图片长度、图片宽度、图片通道数

图片的通道数是什么?

描述一个像素点,如果是灰度图,那么只需要一个数值来描述它,就是单通道

如果一个像素点,有RGB三种颜色来描述它,及时三通道

灰度图:单通道,[长,宽,1]

彩色图片:三通道,[长,宽,3] 像素点为 长 X 宽 X 3

inserte la descripción de la imagen aquí

2、张量形状

在TensorFlow中如何用张量表示一张图片呢?

一张图片可以被表示成一个3D张量,即其形状为[height,width, channel],height就表示高,width表示宽,channel表示通道数。我们会经常遇到3D和4D的表示

  1. 单个图片:[height, width, channel] 3D张量
  2. 多个图片:[batch,height,width, channel],batch表示一个批次的张量数量 4D张量

3.2.2、图片特征值处理

为什么要缩放图片到统一大小?

在进行图像识别的时候,每个图片样本的特征数量要保持相同。所以需要将所有图片张量大小统一转换

缩小放大图片

tf.image**.resize_images**(images, size)

  1. images:4-D形状[batch, height, width, channels]或3-D形状的张量[height, width, channels]的图片数据

  2. size:1-D int32张量:new_height,new_width,图像的新尺寸

  3. 返回4-D格式或者3-D格式图片

    存储:unit8(节省空间)
    矩阵计算:float32(提高精度)

3.2.3、案例:狗图片读取

流程:
1)构造文件名队列
2)读取与解码,使样本的形状和类型统一
3)批处理,一次性处理多张图片

def picture_read(file_list):
	#1、构建文件名队列
	file_queue=tf.train.string_input_producer(file_list)

	#2、文件读取与解码
	reader=tf.WholeFileReader() # 图片的读取器
	# key是文件名,value是一张图片的原始编码形式
	key,value=reader.read(file_queue) # 图片的读取
	print("key:", key)
	print("value:", value)

	# 解码阶段
	image=tf.image.decode_jpeg(value) # 解码jepg格式
	print('image:',image)

	# 图片形状,类型修改
	image_resize=tf.image.resize_images(image,[200,200]) # 统一行列为200
	print('image_resize:',image_resize)

	# 静态形状修改
	image_resize.set_shape(shape = [200,200,3]) # 能用静态形状就用静态,不行再用动态

	# 3、批处理(一次性处理多张图片) 这里1个线程处理100张图片
	image_batch=tf.train.batch([image_resize],batch_size = 100,num_threads = 1,capacity = 100)
	print("image_batch:", image_batch)

	# 开启会话
	with tf.Session() as sess:
		# 创建线程协调员
		coord=tf.train.Coordinator()
		# 开启线程
		threads=tf.train.start_queue_runners(sess=sess,coord = coord)
		key_new, value_new, image_new, image_resize_new, image_batch_new = sess.run([key, value, image, image_resize, image_batch])
		print("key_new:", key_new)
		print("value_new:", value_new)
		print("image_new:", image_new)
		print("image_resize_new:", image_resize_new)
		print("image_batch_new:", image_batch_new)

		# 回收线程,如果不回收,会一直占用系统资源
		coord.request_stop() # 停止线程
		coord.join(threads)  # 回收线程

	pass


if __name__ == '__main__':
	file_name=os.listdir('./data/image/dog')
	# 构造路径 + 文件名的列表
	file_list=[os.path.join('./data/image/dog',file) for file in file_name]
	print(file_name)
	print(file_list)
	picture_read(file_list)
    
'''
['dog.1.jpg', 'dog.10.jpg', 'dog.100.jpg', 'dog.11.jpg', 'dog.12.jpg', 'dog.13.jpg', 'dog.14.jpg', 'dog.15.jpg', ....., 'dog.99.jpg']
['./data/image/dog\\dog.1.jpg', './data/image/dog\\dog.10.jpg', './data/image/dog\\dog.100.jpg', './data/image/dog\\dog.11.jpg', './data/image/dog\\dog.12.jpg', './data/image/dog\\dog.13.jpg', './data/image/dog\\dog.14.jpg', './data/image/dog\\dog.15.jpg',...., './data/image/dog\\dog.99.jpg']
key: Tensor("ReaderReadV2:0", shape=(), dtype=string)
value: Tensor("ReaderReadV2:1", shape=(), dtype=string)
image: Tensor("DecodeJpeg:0", shape=(?, ?, ?), dtype=uint8)
image_resize: Tensor("resize_images/Squeeze:0", shape=(200, 200, ?), dtype=float32)
image_batch: Tensor("batch:0", shape=(100, 200, 200, 3), dtype=float32)
key_new: b'./data/image/dog\\dog.50.jpg'
value_new: b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00\xff\xdb\x00C\x00\n\x07\x07\x08\x07\x06\n\x08\x08\x08\x0b\n\n\x0b\x0e\x18\x10\x0e\r\r\x0e\x1d\x15\x16\x11\x18#\x1f%$"\x1f"!&+7/&)4)!"0A149;>>>%.DIC<H7=>;\xff\xdb\x00C\x01\n\x0b\x0b\x0e\r\x0e\x1c\x10\x10\x1c;("(;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;\xff\xc0\x00\x11\x08\x00\xc7\x00\x9d\x03\x01"\x00\x02\x11\x01\x03\x11\x01\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x10\x00\x02\x01\x03\x03\x02\x04\x03\x05\x05\x04\x04\x00\x00\x01}\x01\x02\x03\x00\x04\x11\x05\x12!1A\x06\x13Qa\x07"q\x142\x81\x91\xa1\x08#B\xb1\xc1\x15R\xd1\xf0$3br\x82\t\n\x16\x17\x18\x19\x1a%&\'()*456789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xc4\x00\x1f\x01\x00\x03\x01\x01\x01\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xc4\x00\xb5\x11\x00\x02\x01\x02\x04\x04\x03\x04\x07\x05\x04\x04\x00\x01\x02w\x00\x01\x02\x03\x11\x04\x05!1\x06\x12AQ\x07aq\x13"2\x81\x08\x14B\x91\xa1\xb1\xc1\t#3R\xf0\x15br\xd1\n\x16$4\xe1%\xf1\x17\x18\x19\x1a&\'()*56789:CDEFGHIJSTUVWXYZcdefghijstuvwxyz\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x92\x93\x94\x95\x96\x97\x98\x99\x9a\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xff\xda\x00\x0c\x03\x01\x00\x02\x11\x03\x11\x00?'
image_new: [[[ 62  78  67]
  [ 42  58  47]
  [ 69  85  74]
  ...
  [193 223 225]
  [194 221 230]
  [149 172 188]]

 [[ 55  71  60]
  [ 46  62  51]
  [ 56  72  61]

  ...
  [231 231 231]
  [231 231 231]
  [231 231 231]]]
image_resize_new: [[[ 62.        78.        67.      ]
  [ 46.3       62.3       51.3     ]
  [ 57.39      73.39      62.39    ]
  ...
  [231.       231.       231.      ]
  [231.       231.       231.      ]
  [231.       231.       231.      ]]]
  
image_batch_new: [[[[  0.          0.          0.       ]
   [  0.          0.          0.       ]
   [  0.          0.          0.       ]
   ...
  [[125.09195   128.09195   137.09195  ]
   [171.11003   174.03503   183.26003  ]
   [129.0711    131.0711    143.2211   ]
   ...
   [ 15.224976   15.224976   15.224976 ]
   [ 12.149994   12.149994   12.149994 ]
   [ 11.         11.         11.       ]]]

   [ 77.06506    45.09503    13.125    ]
   [ 74.14496    43.14496    15.1449585]
   [ 78.745026   47.745026   18.745026 ]]]]

Process finished with exit code 0

'''    

3.3、二进制数据

3.3.1、CIFAR10二进制数据集介绍

CIFAR10数据集官网: https://www.cs.toronto.edu/~kriz/cifar.html

数据集分为五个训练批次和一个测试批次,每个批次有 10000 张图像。测试批次恰好包含来自每个类别的 1000 个随机选择的图像。训练批次包含随机顺序的剩余图像,但一些训练批次可能包含来自一个类的图像多于另一个。在它们之间,训练批次恰好包含来自每个类别的 5000 张图像

inserte la descripción de la imagen aquí

二进制版本数据文件

二进制版本包含文件data_batch_1.bin,data_batch_2.bin,…,data_batch_5.bin以及test_batch.bin

cifar10 的特征值是 image(3072Bytes) 目标值是 label 0-9 (1Bytes)

这些文件中的每一个格式如下,数据中每个样本包含了特征值和目标值:

<1×标签><3072×像素>

<1×标签><3072×像素>
第一个字节是第一个图像的标签,它是一个0-9范围内的数字。接下来的3072个字节是图像像素的值。前1024个字节是红色通道值,下1024个绿色,最后1024个蓝色。值以行优先顺序存储,因此前32个字节是图像第一行的红色通道值。每个文件都包含10000个这样的3073字节的“行"图像,但没有任何分隔行的限制。因此每个文件应该完全是30730000字节长。
即一个样本的形式为: 1+1024r+1024g+1024b=3073个字节

3.3.2、CIFAR10二进制数据读取

流程分析

1、构建文件名队列

file_queue=tf.train.string_input_producer(file_list)

2、读取与解码

reader=tf.FixedLengthRecordReader(3073)

key,value=reader.read(file_queue)

decoded=tf.decoded_raw(value,tf.uint8)

对tensor对象进行切片 label

一个样本image(3072字节=1024r+1024g+1024b)

[[r[32,32]],[g[32,32]],[b[32,32]]] 32x32=1024

shape=(3,32,32) = (channels,height,width)

故需要转换为TensorFlow的图像表示(height,width,channels)

tf.transpose(image,[a,b,c])

如 image_new=tf.transpose(image,[1,2,0]) 参数二是将image的原来索引位置,换成现在对应的索引。

即image_new 0,1,2的位置的值,对应image 1,2,0位置的值

3、批处理

tf.train.batch(tensors, batch_size, num_threads = 1, capacity = 32,name=None)

NHWC与NCHW

在读取设置图片形状的时候有两种格式:

设置为“NHWC"时,排列顺序为 [batch, height, width,channels];

设置为“NCHW"时,排列顺序为[batch, channels, height, width]。

其中N表示这批图像有几张,H表示图像在竖直方向有多少像素,W表示水平方向像素数,C表示通道数。

Tensorflow默认的[height, width, channel]

class Cifar(object):

	def __init__(self):
		# 初始化操作
		self.height=32
		self.width=32
		self.channels=3

		# 字节数
		self.image_bytes=self.height*self.width*self.channels # 图片像素数
		self.label_bytes=1 # 标签数
		self.all_bytes=self.label_bytes+self.image_bytes # 总字节数

	def read_and_decode(self,file_list):
		# 1、构造文件名队列
		file_queue=tf.train.string_input_producer(file_list)

		# 2、读取与解码
		# 读取阶段
		reader=tf.FixedLengthRecordReader(self.all_bytes)
		# key 文件名,value一个样本
		key,value=reader.read(file_queue)
		print('key: ',key)
		print('value: ',value)

		# 解码阶段
		decode=tf.decode_raw(value,tf.uint8)
		print('decode: ',decode)
		# 将目标值和特征值切片分开,即标签和通道分开。tf.slice(data,起始位置,个数)
		label=tf.slice(decode,[0],[self.label_bytes])
		image=tf.slice(decode,[self.label_bytes],[self.image_bytes])
		print('label: ',label)
		print('image: ',image)
		# 调整图片形状
		image_reshaped=tf.reshape(image,shape = [self.channels,self.height,self.width])
		print('image_reshaped: ',image_reshaped)

		# 转置,转成tf图片的表示格式 height,width,channels
		image_transposed=tf.transpose(image_reshaped,[1,2,0])
		print('image_transposed: ',image_transposed)

		# 跳转图像类型,uint8转为float32,调高精度
		image_cast=tf.cast(image_transposed,tf.float32)

		# 3、批处理
		label_batch,image_batch=tf.train.batch([label,image_cast],batch_size = 100,num_threads = 1,capacity = 100)
		print('label_batch: ',label_batch)
		print('image_batch: ',image_batch)

		# 开启会话
		with tf.Session() as sess:
			print('------------------开启会话------------------')
			# 开启线程
			coord=tf.train.Coordinator() # 协调器
			threads=tf.train.start_queue_runners(sess=sess,coord = coord)

key_new,value_new,decode_new,label_new,image_new,image_reshaped_new,image_transposed_new,label_batch_new,image_batch_new=sess.run([key,value,decode,label,image,image_reshaped,image_transposed,label_batch,image_batch])
			print('key_new: ',key_new)
			print('value_new: ',value_new)
			print('decode_new',decode_new)
			print('label_new',label_new)
			print('image_new',image_new)
			print('image_reshaped_new\n',image_reshaped_new)
			print('image_transposed_new\n',image_transposed_new)
			print('label_batch_new\n',label_batch_new)
			print('image_batch_new\n',image_batch_new)

			# 回收线程
			coord.request_stop()
			coord.join(threads)
		return None

if __name__ == '__main__':
	file_name=os.listdir('./data/cifar-10-batches-bin')
	# 构造路径 + 文件名的列表
	file_list=[os.path.join('./data/cifar-10-batches-bin',file) for file in file_name if file[-3:]=='bin']
	print('file_llist: ',file_list)
	#实例化Cifar类
	cifar=Cifar()
	cifar.read_and_decode(file_list)
    
'''
file_llist:  ['./data/cifar-10-batches-bin\\data_batch_1.bin', './data/cifar-10-batches-bin\\data_batch_2.bin', './data/cifar-10-batches-bin\\data_batch_3.bin', './data/cifar-10-batches-bin\\data_batch_4.bin', './data/cifar-10-batches-bin\\data_batch_5.bin', './data/cifar-10-batches-bin\\test_batch.bin']
key:  Tensor("ReaderReadV2:0", shape=(), dtype=string)
value:  Tensor("ReaderReadV2:1", shape=(), dtype=string)
decode:  Tensor("DecodeRaw:0", shape=(?,), dtype=uint8)
label:  Tensor("Slice:0", shape=(1,), dtype=uint8)
image:  Tensor("Slice_1:0", shape=(3072,), dtype=uint8)
image_reshaped:  Tensor("Reshape:0", shape=(3, 32, 32), dtype=uint8)
image_transposed:  Tensor("transpose:0", shape=(32, 32, 3), dtype=uint8)
label_batch:  Tensor("batch:0", shape=(100, 1), dtype=uint8)
image_batch:  Tensor("batch:1", shape=(100, 32, 32, 3), dtype=float32)
------------------开启会话------------------
key_new:  b'./data/cifar-10-batches-bin\\data_batch_1.bin:0'
value_new:  b'\x06;+2Dbw\x8b\x91\x95\x95\x83}\x8e\x90\x89\x81\x89\x86|\x8b\x8b\x85\x88\x8b\x98\xa3\xa8\x9f\x9e\x9e\x98\x94\x10\x00\x123Xx\x80\x7f~tjeiqmpwmi}\x7fz\x83|y\x83\x84\x85\x85{wz\x19\x101Sn\x81\x82yqppji\x80|\x82\x7fzsx\x82\x83\x8b\x7f~\x7f\x82\x8e\x82vxm!&Wjsuriky}mq\x92\x85\x7fvu\x7fz\x84\x89\x][SME7;:A;.9h\x8cTH'
decode_new [  6  59  43 ... 140  84  72]
label_new [6]
image_new [ 59  43  50 ... 140  84  72]
image_reshaped_new
 [[[ 59  43  50 ... 158 152 148]
  [ 16   0  18 ... 123 119 122]
  [ 25  16  49 ... 118 120 109]
  ...
  [ 96  34  26 ...  70   7  20]
  [ 96  42  30 ...  94  34  34]
  [116  94  87 ... 140  84  72]]]
image_transposed_new
 [[[ 59  62  63]
  [ 43  46  45]
  [ 50  48  43]
  ...
  [216 184 140]
  [151 118  84]
  [123  92  72]]]
  
label_batch_new
[[6]
 [0]
 [2]
 [7]
 [2]
 ....
 [2]
 [8]]
image_batch_new 
[[[[ 29.  43.  10.]
   [ 22.  36.   4.]
   [ 25.  37.  16.]
   ...
   [197. 219. 137.]
   [198. 219. 137.]
   [199. 222. 140.]] 
   ....]]]]
  
'''  

3.4、tfrecords读取

3.4.1、什么是TFRecords文件

TFRecords其实是一种二进制文件,虽然它不如其他格式好理解,但是它能更好的利用内存,更方便复制和移动,并且不需要单独的标签文件。即tfrecords 特征值和目标值是绑定在一起的
使用步骤:

  1. 获取数据
  2. 将数据填入到Example协议内存块(protocol buffer)
  3. 将协议内存块序列化为字符串,并且通过tf.python_io.TFRecordwriter写入到TFRecords文件。

文件格式 * . tfrecords

3.4.2、Example结构解析

Example:
    features {
    
    
        feature{
    
    
            key: "iamge"
            value:{
    
    
                bytes_list {
    
    
                    value: '\x06;+2Dbw\x8b\x91\x95\x95\x83}\x8e\x90\x89\x81\x89\x86|\x8b\x8b'
            	}
       	 }
    }
    
     feature{
    
    
            key: "label"
            value:{
    
    
                int64_list {
    
    
                    value: 9
            	}
       	 }
    }
}    

   
  1. tf.train.Example协议内存块(protocol buffer)(协议内存块包含了字段Features)
  2. Features包含了一个Feature字段
  3. Feature中包含要写入的数据、并指明数据类型。
    • 这是一个样本的结构,批数据需要循环存入这样的结构。 即一个example就是一个样本

example = tf.train.Example(features=tf.train.Features(feature={

“image” : tf.train.Feature(bytes_list=tf.train.BytesList(value=[Bytes])),
“label” : tf.train.Feature(int64_list=tf.train.Int64List(value=[Value]))

}))

  • tf.train.Example(features=None)
    • 写入tfrecords文件
    • features: tf.train.Features类型的特征实例
    • return: example格式协议块
  • tf.train.Features(feature=None)
    • 构建每个样本的信息键值对
    • feature:字典数据,key为要保存的名字
    • value为tf.train.Feature实例
    • return: Features类型
  • tf.train.Feature(options)
    • options:
      • bytes_list=tf.train. BytesList(value=[Bytes])
      • int64_list=tf.trai.Int64List(value=[Value])
    • 支持存入的类型如下
    • tf.train.Int64List(value=[Value]) 整型
    • tf.train.BytesList(value=[Bytes]) 字节
    • tf.train.FloatList(value=[value]) 浮点型

这种example结构很好地实现了数据和标签(训练的类别标签)或者其他属性数据存储在同一个文件中

example.SerializeToString() 将example 序列化到本地

3.4.1、tfrecords文件存储

  1. 构造存储实例,tf.python_io.TFRecordWriter(path)
    • 写入tfrecords文件
    • path: TFRecords文件的路径
    • return:写文件
      • method方法
        • write(record):向文件中写入一个example
        • close():关闭文件写入器
  2. 循环将数据填入到Example协议内存块(protocol buffer)
class Cifar(object):

   def __init__(self):
      # 初始化操作
      self.height=32
      self.width=32
      self.channels=3

      # 字节数
      self.image_bytes=self.height*self.width*self.channels # 图片像素数
      self.label_bytes=1 # 标签数
      self.all_bytes=self.label_bytes+self.image_bytes # 总字节数

   def read_and_decode(self,file_list):
      # 1、构造文件名队列
      file_queue=tf.train.string_input_producer(file_list)

      # 2、读取与解码
      # 读取阶段
      reader=tf.FixedLengthRecordReader(self.all_bytes)
      # key 文件名,value一个样本
      key,value=reader.read(file_queue)

      # 解码阶段
      decode=tf.decode_raw(value,tf.uint8)
      # 将目标值和特征值切片分开,即标签和通道分开。tf.slice(data,起始位置,个数)
      label=tf.slice(decode,[0],[self.label_bytes])
      image=tf.slice(decode,[self.label_bytes],[self.image_bytes])
      # 调整图片形状
      image_reshaped=tf.reshape(image,shape = [self.channels,self.height,self.width])
      # 转置,转成tf图片的表示格式 height,width,channels
      image_transposed=tf.transpose(image_reshaped,[1,2,0])
      # 跳转图像类型,uint8转为float32
      image_cast=tf.cast(image_transposed,tf.float32)
      
        # 3、批处理
      label_batch,image_batch=tf.train.batch([label,image_cast],batch_size = 100,num_threads = 1,capacity = 100)

      # 开启会话
      with tf.Session() as sess:
         print('------------------开启会话------------------')
         # 开启线程
         coord=tf.train.Coordinator() # 协调器
         threads=tf.train.start_queue_runners(sess=sess,coord = coord)
         label_batch_new,image_batch_new=sess.run([label_batch,image_batch])
         # 回收线程
         coord.request_stop()
         coord.join(threads)
      return label_batch_new,image_batch_new

   def write_to_tfrecords(self,label_batch,image_batch):
      # 将样本的特征值和目标值写入tfrecords文件
      with tf.python_io.TFRecordWriter('./temp/cifar10/cifar10.tfrecords') as tfWriter:
         # 循环构造example对象,并序列化写入文件
         for i in range(label_batch.size):
            image=image_batch[i].tostring() # 序列化
            label=label_batch[i][0] # [i][0]取出一维数组的值
            example = tf.train.Example(features = tf.train.Features(feature = {
    
    
               "image": tf.train.Feature(bytes_list = tf.train.BytesList(value=[image])),
               "label": tf.train.Feature(int64_list = tf.train.Int64List(value=[label]))
            }))
            # 将序列化后的example写入到cifar10.tfrecords文件中
            tfWriter.write(example.SerializeToString())
            
if __name__ == '__main__':
	file_name=os.listdir('./data/cifar-10-batches-bin')
	# 构造路径 + 文件名的列表
	file_list=[os.path.join('./data/cifar-10-batches-bin',file) for file in file_name if file[-3:]=='bin']
	print('file_llist: ',file_list)
	#实例化Cifar类
	cifar=Cifar()
	label_batch,image_batch=cifar.read_and_decode(file_list)
	cifar.write_to_tfrecords(label_batch,image_batch)            

3.4.2、tfrecords文件读取

读取这种文件整个过程与其他文件一样,只不过需要有个解析Example的步骤。从TFRecords文件中读取数据,可以使用tf.TFRecordReader的 tf.parse_single_example解析器。这个操作可以将Example协议内存块(protocol buffer)解析为张量。

#多了解析example的一个步骤
feature = tf.parse_single_example( values,features={
    
    
"image" : tf.FixedLenFeature([], tf.string),
"label" : tf.FixedLenFeature([], tf.int64)
})
  • tf.parse_single_example(serialized, features=None, name=None)
    • 解析一个单一的Example原型
    • serialized:标量字符串Tensor,一个序列化的Example
    • features: dict字典数据,键为读取的名字,值为FixedLenFeature
    • return:一个键值对组成的字典,键为读取的名字
  • tf.FixedLenFeature(shape, dtype)
    • shape:输入数据的形状,一般不指定,为空列表
    • dtype:输入数据类型,与存储进文件的类型要一致。
    • 类型只能是float32, int64, string(对应bytes类型)

tfrecords文件读取步骤分析

  1. 构造文件名队列
  2. 读取与解码
    1. 读取
    2. 解析example
    3. 解码
  3. 批处理
  4. 开启会话
	def write_to_tfrecords(self,label_batch,image_batch):
		# 将样本的特征值和目标值写入tfrecords文件
		with tf.python_io.TFRecordWriter('./temp/cifar10/cifar10.tfrecords') as tfWriter:
			# 循环构造example对象,并序列化写入文件
			for i in range(label_batch.size):
				image=image_batch[i].tostring() # 序列化
				label=label_batch[i][0] # [i][0]取出一维数组的值
				example = tf.train.Example(features = tf.train.Features(feature = {
    
    
					"image": tf.train.Feature(bytes_list = tf.train.BytesList(value=[image])),
					"label": tf.train.Feature(int64_list = tf.train.Int64List(value=[label]))
				}))
				# 将序列化后的example写入到cifar10.tfrecords文件中
				tfWriter.write(example.SerializeToString())

	def read_tfrecords(self,file_name):
		# 1、构造文件名队列
		file_queue=tf.train.string_input_producer([file_name])
		# 2、读取与解码
		tfReader=tf.TFRecordReader() # TFRecord读取器
		key,value=tfReader.read(file_queue)
		# 解析example
		feature=tf.parse_single_example(value,features = {
    
    
			"image":tf.FixedLenFeature([],tf.string),
			"label":tf.FixedLenFeature([],tf.int64)
		})
		image=feature["image"]
		label=feature["label"]
		print('read_tf_image:\n',image)
		print('read_tf_label:\n',label)

		# 解码
		image_decoded=tf.decode_raw(image,tf.uint8)
		print('image_decoded\n',image_decoded)
		# 图像形状调整,动态调整,调整为tf支持的格式
		image_reshaped=tf.reshape(image_decoded,[self.height,self.width,self.channels])
		print('image_reshaped\n',image_reshaped)

		# 3、批处理
		image_batch,label_batch=tf.train.batch([image_reshaped,label],batch_size = 100,num_threads = 1,capacity = 100)
		print('image_batch\n',image_batch)
		print('label_batch\n',label_batch)

		# 4、开启会话
		with tf.Session() as sess:
			# 开启线程
			# 协调器
			coord=tf.train.Coordinator()
			threads=tf.train.start_queue_runners(sess=sess,coord = coord)

			image_new,label_new,image_decoded_new,image_reshaped_new,image_batch_new,label_batch_new=sess.run([image,label,image_decoded,image_reshaped,image_batch,label_batch])
			print('image_new\n',image_new)
			print('label_new\n',label_new)
			print('image_decoded_new\n',image_decoded_new)
			print('image_reshaped_new\n',image_reshaped_new)
			print('image_batch_new\n',image_batch_new)
			print('label_batch_new\n',label_batch_new)

			# 线程回收
			coord.request_stop()
			coord.join(threads)

		return None
    
if __name__ == '__main__':
	path='./temp/cifar10/cifar10.tfrecords'
	cifar.read_tfrecords(path)

3.5、神经网络基础

3.5.1、定义

**人工神经网络(Artificial Neural Network,简写为ANN)也简称为神经网络(NN)。**是一种模仿生物神经网络(动物的中枢神经系统,特别是大脑)结构和功能的计算模型。经典的神经网络结构包含三个层次的神经网络。分别为输入层,输出层以及隐藏层。

inserte la descripción de la imagen aquí

其中每层的圆圈代表一个神经元,隐藏层和输出层的神经元有输入的数据计算后输出,输入层的神经元只是输入

神经网络的特点:

  • 每个连接都有个权值
  • 同一层神经元之间没有连接
  • 最后的输出结构对应的层也称之为全连接层

那么为什么设计这样的结构呢?首先从一个最基础的结构说起,神经元。以前也称之为感知机。神经元就是要模拟人的神经元结构。

inserte la descripción de la imagen aquí

一个神经元通常具有多个树突,主要用来接受传入信息;而轴突只有一条,轴突尾端有许多轴突末梢可以给其他多个神经元传递信息。轴突末梢跟其他神经元的树突产生连接,从而传递信号。这个连接的位置在生物学上叫做**"突触”**。

感知机(PLA : Perceptron Learning Algorithm)

感知机就是模拟这样的大脑神经网络处理数据的过程。感知机模型如下图:

inserte la descripción de la imagen aquí

感知机是一种最基础的分类模型,类似于逻辑回归,不同的是,**感知机的激活函数用的是sign,而逻辑回归用的sigmoid。**感知机也具有连接的权重和偏置

inserte la descripción de la imagen aquí

3.5.2、神经网络原理

inserte la descripción de la imagen aquí

神经网络解决多分类问题最常用的方法是设置n个输出节点,其中n为类别的个数。

任意事件发生的概率都在0和1之间,且总有某一个事件发生(概率的和为1)。如果将分类问题中“一个样例属于某一个类别”看成一个概率事件,那么训练数据的正确答案就符合一个概率分布。如何将神经网络前向传播得到的结果也变成概率分布呢? Softmax回归就是一个非常常用的方法。

softmax回归

softmax回归将神经网络输出转换成概率结果

inserte la descripción de la imagen aquí

softmax公式的理解

# 假设输出结果为:2.3,4.1,5.6
# softmax的计算输出结果为:
y1_p = e^2.3/(e^2.3+e^4.1+e^5.6)
y1_p = e^4.1/(e^2.3+e^4.1+e^5.6)
y1_p = e^5.6/( e^2.3+e^4.1+e^5.6)

这样子就把神经网络的输出也变成了一个概率输出

inserte la descripción de la imagen aquí

交叉熵损失函数: 衡量神经网络预测的概率和真实结果的概率之间的距离

交叉熵适合用于一个样本对应一个目标值

inserte la descripción de la imagen aquí

为了能够衡量距离,目标值需要进行one-hot编码,能与概率值――对应,如下图

inserte la descripción de la imagen aquí

计算

-[0log(0.10)+0log(0.05)+0log(0.15)+0log(0.10)+0log(0.05)+0log(0.20)+1log(0.10)…]

上述的结果为-1log(0.10),那么为了减少这一个样本的损失。神经网络应该怎么做?

答:提高对应目标值为1的位置输出概率大小。

损失大小

神经网络最后的损失为平均每个样本的损失大小。

即对所有样本的损失求和取其平均值

softmax、交叉熵损失API

tf.nn.softmax_cross_entropy_with_logits(labels=None, logits=None, name=None)

  • abels:标签值(真实值)
  • logits:样本加权之后的值
  • return:返回损失值列表

损失大小求平均

tf.reduce_mean(input_tensor)

计算张量的尺寸的元素平均值

交叉熵的优化:梯度下降

3.5.3、案例:minst手写数字识别

数据集介绍

inserte la descripción de la imagen aquí

文件说明:

  • train-images-idx3-ubyte.gz: training set images(9912422 bytes)
  • train-labels-idx1-ubyte.gz: training set labels (28881 bytes)
  • t10k-images-idx3-ubyte.gz: test set images (1648877 bytes)
  • t10k-labels-idx1-ubyte.gz: test set labels (4542 bytes)

网址: http://yann.lecun.com/exdb/mnist

特征值

Mnist数据集可以从官网下载,网址: http://yann.lecun.com/exdb/mnist/下载下来的数据集被分成两部分:55000行的训练数据集(mnist.train)和10000行的测试数据集 (mnist.test)。每一个MNIST数据单元有两部分组成:一张包含手写数字的图片和一个对应的标签。我们把这些图片设为"xs",把这些标签设为"ys”。训练数据集和测试数据集都包含xs和ys,比如训练数据集的图片是mnist.train.images,训练数据集的标签是mnist.train.labels。

inserte la descripción de la imagen aquí

我们可以知道图片是黑白图片,每一张图片包含28像素X28像素。我们把这个数组展开成一个向量,长度是28x28 = 784。因此,在MNIST训练数据集中,mnist.trajn.images是一个形状为[60000,784]的张量。
inserte la descripción de la imagen aquí

目标值

MNIST中的每个图像都具有相应的标签,目标值:0到9之间的数字表示图像中绘制的数字。用的是one-hot编码
nn[0,0,0,1,0,0,0,0,0,0] mnist.train.labels [55000,10]

inserte la descripción de la imagen aquí

minst数据获取API

TensorFlow框架自带了获取这个数据集的接口,所以不需要自行读取。

  • from tensorflow.examples.tutorials.mnist import input_data
  • mnist = input_data.read_data_sets(path, one_hot=True)
    • mnist.train.next_batch(100)(提供批量获取功能)
    • mnist.train.images、labels
    • mnist.test.images、labels
from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets('mnist_data', one_hot=True)
print(mnist.train.next_batch(1))
print(mnist.train.images[0])  # 查看特征值
print(mnist.train.labels[0])  # 目标值

mnist手写体识别网络层设计

我们采用只有一层,即最后一个输出层的神经网络,也称之为全连接(full connected) 层神经网络

inserte la descripción de la imagen aquí

全连接层计算:即构造权重和偏置

  1. tf.matmul(a, b, name=None)+bias
    • return:全连接结果,供交叉损失运算
  2. tf.train.GradientDescentOptimizer(learning_rate) :梯度下降(优化交叉熵)
    • learning_rate:学习率
    • method: minimize(loss):最小优化损失

计算准确率:对One-hot概率 求平均值

  1. equal_list = tf.equal(tf.argmax(y_predict,1), tf.argmax(y_label,1) # 1按列,比对预测值和真实值,如果相同置1
  2. accuracy = tf.reduce_mean(tf.cast(equal_list, tf.float32))

全连接分析:

y=w1x1+w2x2+…+b

y_predict[None,10]=X[None,784]*weights[784,10]+bias[10]

error=tf.nn.softmax_cross_entropy_with_logits(labels=y_true, logits=y_predict)

def full_connection():
	# 用全连接对手写数字进行识别
	# 1、准备数据
	mnist=input_data.read_data_sets("./data/mnist_data",one_hot = True)
	#  用占位符定义真实数据
	X=tf.placeholder(dtype = tf.float32,shape = [None,784]) # 特征值
	y_true=tf.placeholder(dtype = tf.float32,shape = [None,10]) # 真实值

	# 2、构建模型 - 全连接
	# y_predict[None,10]=X[None,784]*weights[784,10]+bias[10]
	weights=tf.Variable(initial_value = tf.random_normal(shape = [784,10],stddev = 0.01))
	bias=tf.Variable(initial_value = tf.random_normal(shape = [10],stddev = 0.1))
	y_predict=tf.matmul(X,weights)+bias

	# 3、构造损失函数
	loss_list=tf.nn.softmax_cross_entropy_with_logits(logits = y_predict,labels = y_true)
	loss=tf.reduce_mean(loss_list)

	# 4、优化损失(梯度下降)
	optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss)

	# 5、计算准确率 tf.argmax()计算最大值所在列数
	bool_list=tf.equal(tf.argmax(y_predict,axis = 1),tf.argmax(y_true,axis = 1))
	accuracy=tf.reduce_mean(tf.cast(bool_list,tf.float32))
	# 初始化变量
	init = tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		# 初始化变量
		sess.run(init)

		# 开始训练
		for i in range(100):
			# 获取真实值
			image, label = mnist.train.next_batch(100)
			# 因为optimizer返回的是None 所以用_,来接
			_, loss_value, accuracy_value = sess.run([optimizer, loss, accuracy], feed_dict = {
    
    X: image, y_true: label})

			print("第%d次的损失为%f,准确率为%f" % (i + 1, loss_value, accuracy_value))

	return None

if __name__ == '__main__':
    # 如果你报numpy.ufunc size changed错误,尝试更新一下Numpy的版本
    # pip install numpy==1.16.0
	full_connection()
    
'''
第1次的损失为2.292725,准确率为0.160000
第2次的损失为2.331739,准确率为0.020000
…………………………
第100次的损失为1.510217,准确率为0.730000
'''    

4、卷积神经网络

4.1、卷积神经网络简介

4.1.1、卷积神经网络与传统多层神经网络对比

  1. **传统意义上的多层神经网络是只有输入层、隐藏层、输出层。**其中隐藏层的层数根据需要而定,没有明确的理论推导来说明到底多少层合适
  2. 卷积神经网络(Convolutional Neural Networks, CNN),在原来多层神经网络的基础上,加入了更加有效的特征学习部分,具体操作就是在原来的全连接层前面加入了卷积层、激活层和池化层。卷积神经网络出现,使得神经网络层数得以加深,“深度”学习由此而来。
  3. 通常所说的深度学习,一般指的是这些CNN等新的结构以及一些新的方法(比如新的激活函数Relu等),解决了传统多层神经网络的一些难以解决的问题

输入层
隐藏层:卷积层、激活层、池化层、全连接层
输出层

4.1.2、卷积神经网络发展历史

inserte la descripción de la imagen aquí

  1. 网络结构加深
  2. 增强卷积模块功能
  3. 从分类任务到检测任务
  4. 增加新的功能单元

4.1.3、卷积网络ImageNet比赛错误率

  • lmageNet可以说是计算机视觉研究人员进行大规模物体识别和检测时,最先想到的视觉大数据来源,最初由斯坦福大学李飞飞等人在CVPR 2009的一篇论文中推出,并坡用于替代 PASCAL数据集(后者在数据规模和多样性上都不如lmageNet)和LabelMe数据集(在标准化上不如 ImageNet) 。
  • lmageNet不但是计算机视觉发展的重要推动者,也是这一波深度学习热潮的关键驱动力之一。
  • 截至2016年,ImageNet中含有超过1500万由人手工注释的图片网址,也就是带标签的图片,标签说明了图片中的内容,超过2.2万个类别。

inserte la descripción de la imagen aquí

4.2、卷积神经网络原理

4.2.1、卷积神经网络三个结构

神经网络(neural networks)的基本组成包括输入层、隐藏层、输出层。而卷积神经网络的特点在于隐藏层分为卷积层、激活层和池化层(pooling layer,又叫下采样层subsample)。

  1. 卷积层: 通过在原始图像上平移来提取特征
  2. 激活层: 增加非线性分割能力
  3. 池化层(下采样层): 减少学习的参数,降低网络的复杂度(最大池化和平均池化)
  4. **全连接层:**实现分类效果
  5. **输出层:**进行损失计算并输出分类结果

卷积神经网络的结构

inserte la descripción de la imagen aquí

  • CONV: 卷积层
  • RELU: 激活层
  • POOL: 池化层
  • FC(Full Connection): 全连接层

4.2.2、卷积层(Convolutional Layer)

卷积核又叫 filter、过滤器、模型参数、卷积单元

卷积神经网络中每层卷积层由若干卷积单元(卷积核)组成,每个卷积单元的参数都是通过反向传播算法最佳化得到的。

卷积运算的目的是特征提取,第一层卷积层可能只能提取一些低级的特征如边缘、线条和角等层级,更多层的网络能从低级特征中迭代提取更复杂的特征。

1、卷积核(Filter)的四大要素

  1. 卷积核个数

  2. 卷积核大小

  3. 卷积核步长

  4. 卷积核零填充大小

接下来我们通过计算案例讲解,假设图片是黑白图片(只有一个通道)

2、卷积核计算-大小

卷积核大小一般为 1 * 1 3 * 3 5 * 5

卷积核我们可以理解为一个观察的人,带着若干权重和一个偏置去观察,进行特征加权运算。

下图只有权重,少了偏置,一般情况下都要加上偏置!

inserte la descripción de la imagen aquí

通常的卷积核大小 1,3,5,是经过研究人员实验证明比较好的效果。这个人观察之后会得到一个运算结果,
那么这个人想观察所有这张图的像素怎么办?那就需要平移(即步长):

inserte la descripción de la imagen aquí

3、步长

需要去平移卷积核观察这张图片,需要的参数就是步长

假设移动的步长为一个像素,那么最终这个人观察的结果以下图为例:

5x5的图片,3x3的卷积大小去一个步长运算得到3x3的大小观察结果

inserte la descripción de la imagen aquí

如果移动的步长为2那么结果是这样

5x5的图片,3x3的卷积大小,2个步长运算得到2x2的大小观察结果

inserte la descripción de la imagen aquí

4、卷积核个数

不同的卷积核带的权重和偏置都不一样,即随机初始化的参数

那么如果在某一层结构当中,不止是一个人观察,多个人(卷积核)一起去观察。那就得到多张观察结果。

也就是说,一个卷积核得到一个观察结果,多个卷积核就是多个观察结果

5、零填充大小

Filter观察窗口的大小和移动步长有时会导致超过图片像素宽度!

解决办法:

  1. 不要超出图像宽度的观察结果
  2. 零填充

零填充就是在图片像素外围填充一圈值为0的像素。

inserte la descripción de la imagen aquí

6、计算输出大小

如果已知输入图片形状,卷积核数量,卷积核大小,以及移动步长,那么输出图片形状如何确定?

  1. 输入体积大小H1* W1 * D1
  2. 四个超参数︰
    1. Filter数量K
    2. Filter大小F
    3. 步长S
    4. 零填充大小P
  3. 输出体积大小H2 * W2* D2
    1. H2=(H1- F+2P)/S+1 ((高-过滤器大小+2零填充)/步长+1)
    2. W2= (W1- F+2P)/S+1
    3. D2=k

通过一个例子来理解上面的公式

计算案例:

1、假设已知的条件:输入图像32 * 32 * 1 , 50个Filter,大小为5 * 5,移动步长为1,零填充大小为1。请求出输出大小?
H2= (H1 -F +2P)/S + 1 =(32 - 5+2 * 1)/1 + 1 = 30

w2=(W1-F+2P)/S + 1 =(32 -5+2 * 1)/1 + 1 = 30

D2= K= 50(D2等于过滤器的数量K)
所以输出大小为[30,30,50]

2、假设已知的条件∶输入图像32 * 32 * 1 ,50个Filter,大小为3*3,移动步长为1,未知零填充。输出大小32 * 32,求零填充大小?
H2= (H1 -F +2P)/S + 1 = (32 - 3+2 * P)/1 +1 = 32

w2=(W1 -F+2P)/S+ 1 =(32-3+2 * P)/1 +1 = 32

故P=1

所以零填充大小为:1*1

7、多通道图片如何观察

如果是一张彩色图片,那么就有三种表分别为R,G,B。原本每个人需要带一个3x3或者其他大小的卷积核,现在需要带3张3x3的权重和一个偏置,总共就27个权重。最终每个人还是得出一张结果:

inserte la descripción de la imagen aquí

8、卷积网络API

  1. tf.nn.conv2d(input, filter, strides=, padding=, name=None)
    • 计算给定4-D input和filter张量的2维卷积
    • input:给定的输入张量,具有[batch,heigth,width,channel],类型一定为 float32,64
    • filter:指定过滤器的权重数量,[filter_height, filter_width, in_channels,out_channels]
    • strides: strides = [1, stride,stride,1],步长。 例如,如果步长为1,则strides=[1,1,1,1]
    • padding: “SAME"“,“VALID”,具体解释见下面。
  2. Tensorflow的零填充方式有两种方式,SAME和VALID
    • SAME︰越过边缘取样,取样的面积和输入图像的像素宽度一致。公式:ceil(H/S)
      • H为输入的图片的高或者宽,S为步长
      • 无论过滤器的大小是多少,零填充的数量由API自动计算。
    • VALID:不越过边缘取样,取样的面积小于输入人的图像的像素宽度。不填充。
    • 一般填same , valid如果越过边缘的话,观察结果直接丢弃掉
  3. 在Tensorflow当中,卷积API设置"SAME”之后,如果步长为1,输出高宽与输入大小一样(重要)

4.2.3、激活函数

随着神经网络的发展,大家发现原有的sigmoid等激活函数并不能达到好的效果,所以才去新的激活函数。

  • Relu
  • Tanh
  • sigmoid

不同激活函数网站演示:http://playground.tensorflow.org

Relu函数

inserte la descripción de la imagen aquí

效果:

inserte la descripción de la imagen aquí

Relu激活函数API

  • tf.nn.relu(features, name=None)
    • features: 卷积后加上偏置的结果
    • return: 激活函数的计算结果

为什么采用新的激活函数

  1. Relu优点
    • 有效解决梯度消失问题
    • 计算速度非常快,只需要判断输入是否大于0。SGD(批梯度下降)的求解速度速度远快于sigmoid和tanh
  2. sigmoid缺点
    • 采用sigmoid等函数,计算量相对大,而采用Relu 激活函数,整个过程的计算量节省很多。在深层网络中,sigmoid函数反向传播时,很容易就会出现梯度消失的情况

4.2.4、池化层(Polling)

Pooling层主要的作用是特征提取,通过去掉Feature Map中不重要的样本,进一步减少参数数量。即通过池化层尽可能保留图像的主要特征,不会影响图像模型的最终效果,减少模型的复杂度,避免过拟合现象。

Pooling的方法很多,通常采用最大池化

  1. max_polling:取池化窗口的最大值
  2. avg_polling:取池化窗口的平均值

inserte la descripción de la imagen aquí

池化层计算: H2=(H1- F+2P)/S+1 ((高-过滤器大小+2零填充)/步长+1)

池化层也有窗口的大小以及移动步长,那么之后的输出大小怎么计算? 计算公式同卷积计算公式一样

计算:224x224x64,窗口为2,步长为2 输出结果?

H2 =(224 -2+ 2 * 0)/2 +1 = 112
w2 =(224- 2+ 2 * 0)/2 +1 =112

通常池化层采用2x2大小、步长为2窗口,零填充为默认P=0

例子2:

输入图片大小为200×200,依次经过一层卷积(kernel size 5×5,padding 1,stride 2) ,
pooling (kernel size 3×3,padding 0,stride 1),又一层卷积(kernel size 3×3,padding 1,stride 1)之后,

输出特征图大小为:
A.95
B.96
C.97
D.98
E.99
F.100

答案:C

h2=99 w2=99 d2=5 h3=97 d3=3 h4=97 d4=3

注:卷积层向下取整,池化层向上取整

池化层API

  • tf.nn.max_pool(value,ksize=, strides=, padding=,name=None)
    • 输入上执行最大池数
    • value: 4-D Tensor形状[batch, height,width, channels]
    • channel:并不是原始图片的通道数,而是多少filter观察
    • ksize:池化窗口大小,[1,ksize, ksize,1]
    • strides:步长大小,[1,strides,strides,1]
    • padding:“SAME”",“VALID”,使用的填充算法的类型,默认使用 “SAME”

4.2.5、全连接层

全连接层计算:即构造权重和偏置

  1. tf.matmul(a, b, name=None)+bias
    • return:全连接结果,供交叉损失运算
  2. tf.train.GradientDescentOptimizer(learning_rate) :梯度下降(优化交叉熵)
    • learning_rate:学习率
    • method: minimize(loss):最小优化损失

如全连接:

y=w1x1+w2x2+…+b

y_predict[None,10]=X[None,784]*weights[784,10]+bias[10]

weights=tf.Variable(initial_value = tf.random_normal(shape = [784,10],stddev = 0.01))
bias=tf.Variable(initial_value = tf.random_normal(shape = [10],stddev = 0.1))
y_predict=tf.matmul(X,weights)+bias

4.2.6、卷积神经网络总结

inserte la descripción de la imagen aquí

4.3、案例:CNN-Mnist手写数字识别

4.3.1、网络层设计

自己设计一个简单的卷积神经网络做图像识别。由于神经网络的黑盒子特性,如果想自己设计复杂网络通常还是比较困难的,可以使用一些现有的网络结构如之前的GoogleNet、vGG等等。

简单的网络结构

inserte la descripción de la imagen aquí

具体参数

  1. 第一层
    • 卷积:32个filter、大小5 * 5、strides=1、padding=“SAME”。
    • padding=same 指输出图像和输入一样,故宽高都跟原来的值一样
    • 激活:Relu
    • 池化:大小2x2、strides2
  2. 第二层
    • 卷积:64个filter、大小5 * 5、strides=1、padding=“SAME”
    • 激活:Relu
    • 池化:大小2x2、strides2
  3. 全连接层

经过每一层图片数据大小的变化需要确定,Mnist输入的每批次若干图片数据[None,784],如果要经过卷积计算,需要变成[None, 28, 28,1] , 28 x 28=784

卷积网络API: tf.nn.conv2d( input,filter, strides=,padding=)

  1. 第一层卷积大层

    • c

    • 32个filter 大小F:5 * 5 步长S:1 padding=“SAME”

    • padding=same 指输出图像和输入一样,故宽高都跟原来的值一样

    • 输入图片形状 [betch, heigth,width, channel] ,要求:类型为float32,64

    • input:输入图像[None,28,28,1]

      filter:

      变量initial_value=random_normal(shape=[F,F,channels,K])

      ​ weights = tf.Variable(initial_value=tf.random_normal(shape=[5,5,1,32]))

      ​ bias = tf.Variable(initial_value=tf.random_normal(shape=[32]))

      strides: 步长1

      ​ [1,1,1,1]

      padding: "SAME”
      SAME”︰越过边缘取样

      “VALID”":不越过边缘取样

    • 输出形状:因为是padding=same,故输出宽高跟输入一致

      • [None,28,28,32]
    • 激活层: Relu tf.nn.relu(features, name=None)

    • 池化层: 大小2*2 步长2 ,默认padding=0 tf.nn.max_pool(value,ksize=, strides=, padding=,name=None)

      • 输入形状:[None,28,28,32]
    • 输出形状:[None,14,14,32]

  2. 第二层卷积大层

    • 卷积层: tf.nn.conv2d( input,filter, strides=,padding=)

    • 64个filter 大小5 * 5 步长:1 padding=“SAME”

    • 输入现状: [None,14,14,32]

    • filter:

      变量initial_value=random_normal(shape=[F,F,channels,K])

      ​ weights = tf.Variable(initial_value=tf.random_normal(shape=[5,5,32,64]))

      ​ bias = tf.Variable(initial_value=tf.random_normal(shape=[64]))

      strides: 步长1

      ​ [1,1,1,1]

      padding: "SAME”
      SAME”︰越过边缘取样

      “VALID”":不越过边缘取样

    • 输出形状:因为是padding=same,故输出宽高跟输入一致

      • [None,14,14,64]
    • 激活层: Relu tf.nn.relu(features, name=None)

    • 池化层: 大小2*2 步长2 ,默认padding=0 tf.nn.max_pool(value,ksize=, strides=, padding=,name=None)

      • 输入形状:[None,14,14,64]
    • 输出形状:[None,7,7,64]

  3. 全连接层

    • tf.reshape()
    • [None,7,7,64]-----转换为二阶矩阵-> pool2 = [None,7 * 7 * 64]
    • 最终的目标值形式[None,10]=[None,7 * 7 * 64] * [7 * 7 * 64 ,10](权重)
    • y_predict = tf.matmul(pool2,weights) + bias

CNN-Minst卷积神经网络简单案例:

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

def create_weights(shape):
	# 定义权重和偏置  stddev 标准差
	return tf.Variable(initial_value = tf.random_normal(shape = shape,stddev = 0.01))

def create_model(x):
	# 构建卷积神经网络模型
	# 1、第一卷积大层
	with tf.variable_scope('conv1'):
		# 卷积层
		# 将x[None,784]进行形状上的修改  -1 会自动统计有多少张betch
		input_x=tf.reshape(x,shape = [-1,28,28,1])
		# 定义32个filter和偏置
		conv1_weights=create_weights(shape = [5,5,1,32])
		conv1_bias=create_weights(shape = [32])
		conv1_x=tf.nn.conv2d(input = input_x,filter = conv1_weights,strides = [1,1,1,1],padding="SAME")+conv1_bias

		# 激活层
		relu1_x=tf.nn.relu(conv1_x)

		# 池化层
		pool1_x=tf.nn.max_pool(value =relu1_x,ksize = [1,2,2,1],strides = [1,2,2,1],padding = "SAME")

	# 2、第一卷积大层
	with tf.variable_scope('conv2'):
		# 卷积层
		# 定义64个filter和偏置
		conv2_weights = create_weights(shape = [5, 5, 32, 64])
		conv2_bias = create_weights(shape = [64])
		conv2_x = tf.nn.conv2d(input = pool1_x, filter = conv2_weights, strides = [1, 1, 1, 1],padding = "SAME") + conv2_bias

		# 激活层
		relu2_x = tf.nn.relu(conv2_x)

		# 池化层
		pool2_x = tf.nn.max_pool(value = relu2_x, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = "SAME")

	# 全连接层
	with tf.variable_scope('full_connection'):
		# 改变形状,修改为二维数组类型
		x_fc=tf.reshape(pool2_x,shape = [-1,7*7*64])
		weights_fc=create_weights(shape = [7*7*64,10])
		bias_fc=create_weights(shape = [10])
		y_predict=tf.matmul(x_fc,weights_fc)+bias_fc
	return y_predict

def full_connection():
	# 用全连接对手写数字进行识别
	# 1、准备数据
	mnist=input_data.read_data_sets("./data/mnist_data",one_hot = True)
	#  用占位符定义真实数据
	X=tf.placeholder(dtype = tf.float32,shape = [None,784]) # 特征值
	y_true=tf.placeholder(dtype = tf.float32,shape = [None,10]) # 真实值
	# 2、构建模型 - 全连接
	y_predict=create_model(X)
	# 3、构造损失函数
	loss_list=tf.nn.softmax_cross_entropy_with_logits(logits = y_predict,labels = y_true)
	loss=tf.reduce_mean(loss_list)
	# 4、优化损失(梯度下降)
	optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(loss) # 默认0.01最多
	# 调优,修改学习率,优化器等
	# optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(loss)
	# Adam优化器
	# optimizer=tf.train.AdamOptimizer(learning_rate = 0.01).minimize(loss)
	
	# 5、计算准确率 tf.argmax()计算最大值所在列数
	bool_list=tf.equal(tf.argmax(y_predict,axis = 1),tf.argmax(y_true,axis = 1))
	accuracy=tf.reduce_mean(tf.cast(bool_list,tf.float32))
	# 初始化变量
	init = tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		# 初始化变量
		sess.run(init)
		# 开始训练
		for i in range(300):
			# 获取真实值
			image, label = mnist.train.next_batch(100)
			# 因为optimizer返回的是None 所以用_,来接
			_, loss_value, accuracy_value = sess.run([optimizer, loss, accuracy], feed_dict = {
    
    X: image, y_true: label})
			print("第%d次的损失为%f,准确率为%f" % (i + 1, loss_value, accuracy_value))
	return None

# 准确率  比较输出的结果最大值与真实值最大值所在的位置
    # print(mnist.train.next_batch(1))
    # print(mnist.train.images[0])  # 查看特征值
    # print(mnist.train.labels[0])  # 目标值
    # one - hot  0 1 ...9
 
if __name__ == '__main__':
    # 如果你报numpy.ufunc size changed错误,尝试更新一下Numpy的版本
    # pip install numpy==1.16.0
	full_connection()
    
'''
第66次的损失为2.066249,准确率为0.200000
第67次的损失为1.938220,准确率为0.310000
第68次的损失为1.739915,准确率为0.450000
第69次的损失为1.615815,准确率为0.470000
'''    

网络的优化和改进

  1. 调整学习率、随机初始化的权重和偏置
  2. 调整优化器,优化损失函数
  3. 使用不同的激活函数
  4. 重新设计网络
  5. 使用梯度截断(在训练过程中检查和限制梯度的大小)
  6. 对于深度网络模型,添加batch normalization层或者droupout层
    1. batch normalization层 (批量标准化,让这层的网络输出的权重、偏置或者参数分布归一化,即分布在同样的规律内)
    2. droupout层 (使当前的神经元失效,减低模型的复杂度)
def weight__variables(shape ) :
	w = tf.Variable(tf.random_normal(shape=shape,mean=0.0,stddev=0.1)  # 调整平均值和标准差
	return w

卷积神经网络结构在imagenet比赛对比

inserte la descripción de la imagen aquí

卷积网络其它用途

  1. Yolo: GoogleNet+ bounding boxes
  2. SD: VGG + region proposalso
  3. Faster-RCNN: VGG, ResNet

4.4、案例:验证码图片识别

步骤分析

  1. 计算损失率
    1. 验证码图片(如NZPP)–》一个样本对应四个特征值。–》使用sigmoid交叉熵
    2. 手写数字图片识别((0~9之间的某一个数)–》一个样本对应一个特征值–》使用softmax交叉熵
    3. NZPP–》根据字母的顺序标记 [13,25,15,15] -->[4,26]
    4. –>[ [ 0, 0,0,0,0,o,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0 ], [ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1],[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0],[0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0]]
  2. 数据集
    特征值 目标值怎么用
  3. 如何分类?
    1. 如何比较输出结果和真实值的正确性?如何衡量损失?
      手写数字识别案例
      softmax+交叉嫡
      [4,26] ->[4*26]
      sigmoid交叉嫡
      准确率如何计算?
      核心:对比真实值和预测值最大值所在位置手写
    2. 数字识别案例
      y_predict [None,10]
      tf.argmax(y_predict,axis=1)
      y_predict [None,4,26]
      tf.argmax(y_predict, axis=2/-1)
      [True,
      True,
      True,
      False] -> tf.reduce_all() -> False
  4. 流程分析
    1. 读取图片数据
      • filename ->标签值
    2. 解析csv文件,将标签值NZPP->[13,25,15,15]
    3. 将filename和标签值联系起来
    4. 构建卷积神经网络->y_predict
    5. 构造损失函数
    6. 优化损失
    7. 计算准确率
    8. 开启会话、开启线程

análisis de pasos

Valor propio Valor objetivo – Modelo

Valor de la característica: 6000 imágenes - valor objetivo - correspondiente

  1. leer datos de imagen

    1. clave, valor = lectura (file_queue) clave: nombre de archivo - etiquetas.csv - valor objetivo valor: contenido de una muestra
  2. Analice el archivo CSV y cree una tabla correspondiente al nombre del archivo y el valor de la etiqueta

  3. Correspondencia uno a uno entre el valor característico de una muestra y el valor objetivo

    1. Buscar tabla por nombre de archivo (csv_data)
    2. inserte la descripción de la imagen aquí
  4. Establecer un modelo de red neuronal convolucional == "get y_predict

  5. Calcular la pérdida de entropía de la cruz sigmoidea

  6. mejoramiento

  7. Precisión de cálculo

import tensorflow as tf
import pandas as pd
import numpy as np
import glob

# 1、读取图片数据
# key, value = read(file_queue)
# key: 文件名 - labels.csv - 目标值value:一个样本的内容
def read_pic():
	#1、构建文件名队列
	file_names=glob.glob('./data/GenPics/*.jpg')
	file_queue=tf.train.string_input_producer(file_names)
	#2、读取与解码
	reader=tf.WholeFileReader()
	filename,image=reader.read(file_queue)
	#解码阶段
	decoded_image=tf.image.decode_jpeg(image)
	#更新形状,将图片形状确定下来
	decoded_image.set_shape([20,80,3])
	#修改图片的类型
	cast_image=tf.cast(decoded_image,tf.float32)
	#3、批处理
	filename_batch,image_batch=tf.train.batch([filename,cast_image],batch_size = 100,num_threads = 1,capacity = 200)
	return filename_batch,image_batch

# 2、解析CSV文件,建立文件名和标签值对应表格
def parse_csv():
	# 读取文件
	csv_data=pd.read_csv('./data/GenPics/labels.csv',names = ['file_num','chars'],index_col = 'file_num')
	#根据字母生成对应数字
	# NZPP  [13,25,15,15]
	labels=[]
	for label in csv_data['chars']:
		letter=[]
		for word in label:
			# A在26字母中的序号为0 B为1
			letter.append(ord(word)-ord('A'))  # ord() 返回对应的ASCII数值
		labels.append(letter)

	csv_data['labels']=labels  # 更新labels列的内容

	return csv_data

# 3、将一个样本的特征值和目标值一一对应
# 通过文件名查表(csv_data)
def filename2label(filenames,csv_data):
	labels=[]

	for file_name in filenames:
		file_num="".join((list(filter(str.isdigit,str(file_name))))) # 获取csv的序号,从而找到目标值
		target_labels=csv_data.loc[int(file_num),'labels']  # 目标值
		labels.append(target_labels)
	return np.array(labels)

# 4、建立卷积神经网络模型 == 》得出y_predict
def create_weights(shape):
	# 定义权重和偏置  stddev 标准差
	return tf.Variable(initial_value = tf.random_normal(shape = shape,stddev = 0.01))

def create_model(x):
	# 构建卷积神经网络模型
	# x: [None,20,80,3]
	# 1、第一卷积大层
	with tf.variable_scope('conv1'):
		# 卷积层
		# 定义32个filter和偏置
		conv1_weights=create_weights(shape = [5,5,3,32])
		conv1_bias=create_weights(shape = [32])
		conv1_x=tf.nn.conv2d(input = x,filter = conv1_weights,strides = [1,1,1,1],padding="SAME")+conv1_bias
		# 激活层
		relu1_x=tf.nn.relu(conv1_x)
		# 池化层
		pool1_x=tf.nn.max_pool(value =relu1_x,ksize = [1,2,2,1],strides = [1,2,2,1],padding = "SAME")

	# 2、第一卷积大层
	with tf.variable_scope('conv2'):
		# 卷积层
		# 定义64个filter和偏置
		conv2_weights = create_weights(shape = [5, 5, 32, 64])
		conv2_bias = create_weights(shape = [64])
		conv2_x = tf.nn.conv2d(input = pool1_x, filter = conv2_weights, strides = [1, 1, 1, 1],padding = "SAME") + conv2_bias
		# 激活层
		relu2_x = tf.nn.relu(conv2_x)
		# 池化层
		pool2_x = tf.nn.max_pool(value = relu2_x, ksize = [1, 2, 2, 1], strides = [1, 2, 2, 1], padding = "SAME")

	# 全连接层
	with tf.variable_scope('full_connection'):
		# 改变形状,修改为二维数组类型
		# # 输入[None,10,40,32]-->[None,5,20,64]
		#[None, 5, 20, 64]-->[None, 5 * 20 * 64]
		#[None,5 * 20 * 64]*[5 * 20 * 64,4 * 26] = [None,4 * 26]
		x_fc=tf.reshape(pool2_x,shape = [-1,5*20*64])
		weights_fc=create_weights(shape = [5*20*64,4*26])
		bias_fc=create_weights(shape = [4*26])
		y_predict=tf.matmul(x_fc,weights_fc)+bias_fc
	return y_predict

if __name__ == '__main__':
	filename,image=read_pic()
	csv_data=parse_csv()

	# 1、准备数据
	x=tf.placeholder(tf.float32,shape = [None,20,80,3])
	y_true=tf.placeholder(tf.float32,shape = [None,4*26])
	# 2、构建模型
	y_predict=create_model(x)
	# 3、构建损失函数
	loss_list=tf.nn.sigmoid_cross_entropy_with_logits(labels = y_true,logits = y_predict)
	loss=tf.reduce_mean(loss_list)
	# 4、优化损失
	# optimizer=tf.train.GradientDescentOptimizer(learning_rate = 0.01).minimize(loss) # 梯度下降,最小化
	optimizer=tf.train.AdamOptimizer(learning_rate = 0.1).minimize(loss) # Adam优化器,最小化

	# 5、计算准确率
	equal_list=tf.reduce_all(tf.equal(tf.argmax(tf.reshape(y_predict,shape = [-1,4,26]),axis = 2),
									  tf.argmax(tf.reshape(y_true, shape = [-1, 4,26]), axis = 2)),axis=1)
	accuracy=tf.reduce_mean(tf.cast(equal_list,tf.float32))
	# 初始化变量
	init=tf.global_variables_initializer()

	# 开启会话
	with tf.Session() as sess:
		sess.run(init)
		# 开启线程
		coor=tf.train.Coordinator()
		threads=tf.train.start_queue_runners(sess = sess,coord = coor)
		for i in range(150):
			filename_value,image_value=sess.run([filename,image])
			labels=filename2label(filename_value,csv_data) # 将一个样本的特征值和目标值一一对应
			# 将目标值转换为one-hot编码
			labels_value=tf.reshape(tf.one_hot(labels,depth = 26),[-1,4*26]).eval()
			_,error,accuracy_value=sess.run([optimizer,loss,accuracy],feed_dict = {
    
    x:image_value,y_true:labels_value})
			print('第%d次训练损失为%f,准确率为%f'%(i+1,error,accuracy_value))

		# 回收线程
		coor.request_stop()
		coor.join(threads)

Supongo que te gusta

Origin blog.csdn.net/qq_44231797/article/details/125086565
Recomendado
Clasificación