neural network - ¿Etiquetas de prueba para regresión caffe, flotador no permitido?
neural-network regression (4)
Además de
la respuesta de @ Shai
anterior, escribí una capa
MultiTaskData
que admite etiquetas de tipo
float
.
Su idea principal es almacenar las etiquetas en el campo
float_data
de
Datum
, y
MultiTaskDataLayer
analizará como etiquetas para cualquier número de tareas de acuerdo con el valor de
task_num
y
label_dimension
establecido en
net.prototxt
.
Los archivos relacionados incluyen:
caffe.proto
,
multitask_data_layer.hpp/cpp
,
io.hpp/cpp
.
Puede agregar fácilmente esta capa a su propio café y usarla de esta manera (este es un ejemplo para la tarea de aprendizaje de distribución de etiquetas de expresión facial en la que "exp_label" puede ser vectores de tipo flotante como [0.1, 0.1, 0.5, 0.2, 0.1 ] que representa la distribución de probabilidad de expresiones faciales (clase 5).
name: "xxxNet"
layer {
name: "xxx"
type: "MultiTaskData"
top: "data"
top: "exp_label"
data_param {
source: "expression_ld_train_leveldb"
batch_size: 60
task_num: 1
label_dimension: 8
}
transform_param {
scale: 0.00390625
crop_size: 60
mirror: true
}
include:{ phase: TRAIN }
}
layer {
name: "exp_prob"
type: "InnerProduct"
bottom: "data"
top: "exp_prob"
param {
lr_mult: 1
decay_mult: 1
}
param {
lr_mult: 2
decay_mult: 0
}
inner_product_param {
num_output: 8
weight_filler {
type: "xavier"
}
bias_filler {
type: "constant"
}
}
}
layer {
name: "exp_loss"
type: "EuclideanLoss"
bottom: "exp_prob"
bottom: "exp_label"
top: "exp_loss"
include:{ phase: TRAIN }
}
Estoy haciendo regresión usando caffe, y mis archivos
test.txt
y
train.txt
son así:
/home/foo/caffe/data/finetune/flickr/3860781056.jpg 2.0
/home/foo/caffe/data/finetune/flickr/4559004485.jpg 3.6
/home/foo/caffe/data/finetune/flickr/3208038920.jpg 3.2
/home/foo/caffe/data/finetune/flickr/6170430622.jpg 4.0
/home/foo/caffe/data/finetune/flickr/7508671542.jpg 2.7272
Mi problema es que parece que caffe no permite etiquetas flotantes como 2.0, cuando uso etiquetas flotantes mientras leo, por ejemplo, el archivo
''test.txt''
caffe solo reconoce
un total de 1 imágenes
Cuál está mal.
Pero cuando, por ejemplo, cambio el 2.0 a 2 en el archivo y las siguientes líneas son iguales, caffe ahora da
un total de 2 imágenes
lo que implica que las etiquetas flotantes son responsables del problema.
¿Alguien puede ayudarme aquí? Para resolver este problema, definitivamente necesito usar etiquetas flotantes para la regresión, entonces, ¿alguien sabe sobre una solución o solución para esto? Gracias por adelantado.
EDITAR Para cualquiera que se enfrente a un problema similar, usar caffe para entrenar a Lenet con datos CSV podría ser de ayuda. Gracias a @Shai.
Cuando se usa la capa de entrada del conjunto de datos de imagen (con el backend
lmdb
o
leveldb
) caffe solo admite una etiqueta
entera
por imagen de entrada.
Si desea hacer una regresión y usar etiquetas de punto flotante, debe intentar usar la capa de datos HDF5. Ver por ejemplo esta pregunta .
En python puedes usar el paquete
h5py
para crear archivos hdf5.
import h5py, os
import caffe
import numpy as np
SIZE = 224 # fixed size to all images
with open( ''train.txt'', ''r'' ) as T :
lines = T.readlines()
# If you do not have enough memory split data into
# multiple batches and generate multiple separate h5 files
X = np.zeros( (len(lines), 3, SIZE, SIZE), dtype=''f4'' )
y = np.zeros( (len(lines),1), dtype=''f4'' )
for i,l in enumerate(lines):
sp = l.split('' '')
img = caffe.io.load_image( sp[0] )
img = caffe.io.resize( img, (SIZE, SIZE, 3) ) # resize to fixed size
# you may apply other input transformations here...
# Note that the transformation should take img from size-by-size-by-3 and transpose it to 3-by-size-by-size
# for example
# transposed_img = img.transpose((2,0,1))[::-1,:,:] # RGB->BGR
X[i] = transposed_img
y[i] = float(sp[1])
with h5py.File(''train.h5'',''w'') as H:
H.create_dataset( ''X'', data=X ) # note the name X given to the dataset!
H.create_dataset( ''y'', data=y ) # note the name y given to the dataset!
with open(''train_h5_list.txt'',''w'') as L:
L.write( ''train.h5'' ) # list all h5 files you are going to use
Una vez que tenga todos los archivos
h5
y los archivos de prueba correspondientes que los enumeran, puede agregar una capa de entrada HDF5 a su
train_val.prototxt
:
layer {
type: "HDF5Data"
top: "X" # same name as given in create_dataset!
top: "y"
hdf5_data_param {
source: "train_h5_list.txt" # do not give the h5 files directly, but the list.
batch_size: 32
}
include { phase:TRAIN }
}
Aclaracion
:
Cuando digo "caffe solo admite una etiqueta entera por imagen de entrada" no quiero decir que los contenedores leveldb / lmdb son limitados, me refiero a las herramientas de caffe, específicamente la herramienta
convert_imageset
.
En una inspección más cercana, parece que caffe almacena datos de tipo
Datum
en leveldb / lmdb y la propiedad "label" de este tipo se define como un entero (ver
caffe.proto
), por lo tanto, cuando se usa la interfaz de caffe para leveldb / lmdb, está restringido a un sola etiqueta int32 por imagen.
Terminé transponiendo, cambiando el orden de los canales y usando entradas sin firmar en lugar de flotantes para obtener resultados. Sugiero leer una imagen desde su archivo HDF5 para asegurarse de que se muestre correctamente.
Primero lea la imagen como ints sin firmar:
img = np.array(Image.open(''images/'' + image_name))
Luego cambie el orden de los canales de RGB a BGR:
img = img[:, :, ::-1]
Finalmente, cambie de Altura x Ancho x Canales a Canales x Altura x Ancho:
img = img.transpose((2, 0, 1))
¡Simplemente cambiar la forma revuelve su imagen y arruina sus datos!
Para volver a leer la imagen:
with h5py.File(h5_filename, ''r'') as hf:
images_test = hf.get(''images'')
targets_test = hf.get(''targets'')
for i, img in enumerate(images_test):
print(targets_test[i])
from skimage.viewer import ImageViewer
viewer = ImageViewer(img.reshape(SIZE, SIZE, 3))
viewer.show()
Aquí hay un script que escribí que trata con dos etiquetas (dirección y velocidad) para una tarea de auto sin conductor: https://gist.github.com/crizCraig/aa46105d34349543582b177ae79f32f0
La respuesta de Shai ya cubre guardar etiquetas flotantes en formato HDF5. En caso de que se requiera / prefiera LMDB, aquí hay un fragmento sobre cómo crear un LMDB a partir de datos flotantes (adaptado de this comentario de github):
import lmdb
import caffe
def scalars_to_lmdb(scalars, path_dst):
db = lmdb.open(path_dst, map_size=int(1e12))
with db.begin(write=True) as in_txn:
for idx, x in enumerate(scalars):
content_field = np.array([x])
# get shape (1,1,1)
content_field = np.expand_dims(content_field, axis=0)
content_field = np.expand_dims(content_field, axis=0)
content_field = content_field.astype(float)
dat = caffe.io.array_to_datum(content_field)
in_txn.put(''{:0>10d}''.format(idx) dat.SerializeToString())
db.close()