Тестовые этикетки для регрессионного кофе, поплавок не допускаются?
Я делаю регрессию с помощью caffe, а файлы test.txt
и train.txt
выглядят следующим образом:
/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
Моя проблема заключается в том, что, похоже, caffe не допускает float-меток типа 2.0, когда я использую ярлыки float во время чтения, например, только для файла 'test.txt'
file caffe
распознает
всего 1 изображение
что неверно.
Но когда я, например, меняю 2.0 на 2 в файле и на следующие строки, caffe теперь дает
всего 2 изображения
подразумевая, что метки с плавающей точкой несут ответственность за проблему.
Может ли кто-нибудь помочь мне здесь, чтобы решить эту проблему, мне определенно нужно использовать float-метки для регрессии, так кто-нибудь знает о работе или решении для этого? Спасибо заранее.
ИЗМЕНИТЬ
Для тех, кто сталкивается с аналогичной проблемой, использовать caffe для обучения Lenet с данными CSV может оказаться полезным. Благодаря @Shai.
Ответы
Ответ 1
При использовании входного слоя набора данных изображения (с помощью или leveldb
) caffe поддерживает только один ярлык целочисленный для каждого входного изображения.
Если вы хотите сделать регрессию и использовать метки с плавающей запятой, вы должны попробовать и использовать уровень данных HDF5. См. Например этот вопрос.
В python вы можете использовать пакет h5py
для создания файлов 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
Как только у вас есть все файлы h5
и соответствующие им тестовые файлы, вы можете добавить входной уровень HDF5 к вашему 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 }
}
Разъяснение:
Когда я говорю: "caffe поддерживает только одну целую метку для каждого входного изображения", я не имею в виду, что контейнеры leveldb/lmdb ограничены, я имел в виду инструменты caffe, в частности convert_imageset
.
При ближайшем рассмотрении кажется, что данные хранилища хранятся в типе Datum
в leveldb/lmdb, а свойство label (метка) этого типа определяется как целое число (см. caffe.proto), поэтому при использовании интерфейса caffe для leveldb/lmdb вы ограничены одной меткой int32 для каждого изображения.
Ответ 2
Ответ Shai уже охватывает сохранение меток float в формате HDF5. В случае необходимости/предпочтительности LMDB здесь приведен фрагмент того, как создать LMDB из данных с плавающей запятой (адаптирован из этот комментарий 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()
Ответ 3
Я закончил перенос, переключив порядок каналов и используя unsigned ints, а не floats, чтобы получить результаты. Я предлагаю прочитать изображение из файла HDF5, чтобы убедиться, что оно отображается правильно.
Сначала прочитайте изображение как unsigned ints:
img = np.array(Image.open('images/' + image_name))
Затем измените порядок каналов от RGB до BGR:
img = img[:, :, ::-1]
Наконец, переключитесь с Height x Width x Каналы на каналы x Высота x Ширина:
img = img.transpose((2, 0, 1))
Простое изменение формы будет искажать ваше изображение и разрушать ваши данные!
Чтобы прочитать изображение:
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()
Здесь script я написал, что касается двух ярлыков (руля и скорости) для самозанятого автомобильного задания: https://gist.github.com/crizCraig/aa46105d34349543582b177ae79f32f0
Ответ 4
Помимо @Shai answer выше, я написал MultiTaskData, поддерживающий float
типизированные метки.
Его основная идея - хранить метки в float_data
поле Datum
, а MultiTaskDataLayer
будет анализировать их как метки для любого количества задач в соответствии со значениями task_num
и label_dimension
, установленными в net.prototxt
. Связанные файлы включают в себя: caffe.proto
, multitask_data_layer.hpp/cpp
, io.hpp/cpp
.
Вы можете легко добавить этот слой в свой собственный кофе и использовать его как это (это пример для задачи обучения распределению меток выражения лица, в которой "exp_label" может быть вложенными векторами типа float, такими как [0,1, 0,1, 0,5, 0,2, 0,1], представляющие распределение вероятностей выражения (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 }
}