Пятикратная перекрестная проверка: разделите данные на 5 равных частей, возьмите одну часть для проверки в каждом эксперименте, а остальные используйте для обучения. Опыты усреднялись 5 раз. Как показано выше, в первом эксперименте первый используется как тестовая выборка, а остальные — как обучающая выборка. Во втором эксперименте вторая копия использовалась как тестовая, а остальные — как обучающая. И так далее~
Однако причина довольно проста, но я не буду писать код, например, как мне равномерно разделить данные на5
Поделиться? Как я могу гарантировать, что данные разделены таким образом для каждого эксперимента? Во время обычного обучения данные6:2:2
Разделите на тренировочный набор, проверочный набор и тестовый набор, обучите изображения в тренировочном наборе, сохраните лучшую модель в проверочном наборе и используйте тестовый набор для финального теста. Теперь, когда для перекрестной проверки не задана проверка, как сохранить модель? Далее ответ для всех.
1. Разделите данные на K равных частей
использоватьKFold
своего рода.
class sklearn.model_selection.KFold(n_splits=5, *, shuffle=False, random_state=None) sklearn
Предоставленная функция используется для K-кратной перекрестной проверки.
Предоставить тренировочный набор/тестовый наборпоказательразделить данные. Разделите набор данных на k сгибов (по умолчанию не перемешивайте данные.
Введение параметра
-
n_splits: int, по умолчанию
5
. значит разделить на5
складывать -
shuffle: bool, по умолчанию
False
. Следует ли перемешивать данные перед разделением набора данных.True
перетасовка,False
Не перемешивайте. -
random_state: int, по умолчанию
None
. когдаshuffle
Когда Истинно, еслиrandom_state
Если установлено None, то при каждом запуске кода сегментация полученных данных будет разной.random_state
Если указано, одни и те же данные сегментации могут быть получены при каждом запуске кода, что гарантирует повторяемость эксперимента.random_state
Он может быть установлен в целое число в соответствии с вашими предпочтениями, напримерrandom_state=42
чаще используется. Однажды установленный, он не может быть изменен.
использоватьKFold
Сначала необходимо инициализировать класс, а затем вызывать его методы для реализации разделения данных. Два его метода:
get_n_splits(X=None, y=None, groups=None)
Возвращает количество разделенных итераций в кросс-валидаторе
split(X, y=None, groups=None)
Создайте индекс, чтобы разделить данные на обучающие и тестовые наборы.
X
: массив формы:(n_samples, n_features)
где n_samples — количество образцов, а n_features — количество признаков.
y
: массив формы(n_samples,)
, default=None
. можешь или нет
return
:train
иtest
изпоказатель, обратите внимание, что возвращаемое значение каждой коллекциипоказатель, а не данные
Пример 1: Настройкаshuffle=False
, результат один и тот же каждый раз
from sklearn.model_selection import KFold
import numpy as np
X = np.arange(24).reshape(12,2)
y = np.random.choice([1,2],12,p=[0.4,0.6])
kf = KFold(n_splits=5,shuffle=False) # 初始化KFold
for train_index , test_index in kf.split(X): # 调用split方法切分数据
print('train_index:%s , test_index: %s ' %(train_index,test_index))
Результат: Индекс 5-кратных данных
train_index:[ 3 4 5 6 7 8 9 10 11] , test_index: [0 1 2]
train_index:[ 0 1 2 6 7 8 9 10 11] , test_index: [3 4 5]
train_index:[ 0 1 2 3 4 5 8 9 10 11] , test_index: [6 7]
train_index:[ 0 1 2 3 4 5 6 7 10 11] , test_index: [8 9]
train_index:[0 1 2 3 4 5 6 7 8 9] , test_index: [10 11]
Доступно получение данных и соответствующих тегов по индексу:
fold1_train_data, fold1_train_label = X[train_index], y[train_index]
Пример 2: Настройкаshuffle=True
, каждый раз результат разный
Пример 3: Настройкаshuffle=True
иrandom_state=整数
, результат один и тот же каждый раз
Поэтому рекомендуется использовать случай 3 в реальных условиях, что может обеспечить повторяемость эксперимента и увеличить случайность данных.
Пример 4: Разделение данных реального случая
У меня есть некоторые 3D-данные nii.gz для сегментации, изображения и метки размещены в разных папках. как:
└── 根目录
└── image
│ ├── 1.nii.gz
│ │── 2.nii.gz
│ └── 3.nii.gz
│
── label
│ ├── 1.nii.gz
│ │── 2.nii.gz
│ └── 3.nii.gz
images1 = sorted(glob.glob(os.path.join(data_root, 'ImagePatch', 'l*.nii.gz')))
labels1 = sorted(glob.glob(os.path.join(data_root, 'Mask01Patch', 'l*.nii.gz')))
images2 = sorted(glob.glob(os.path.join(data_root, 'ImagePatch', 'r*.nii.gz')))
labels2 = sorted(glob.glob(os.path.join(data_root, 'Mask01Patch', 'r*.nii.gz')))
data_dicts1 = [{'image': image_name, 'label': label_name}
for image_name, label_name in zip(images1, labels1)]
data_dicts2 = [{'image': image_name, 'label': label_name}
for image_name, label_name in zip(images2, labels2)]
all_files = data_dicts1 + data_dicts2
# 把image和label创建成字典,统一放在列表里
all_files
представляет собой список, содержащий все данные, но каждые данные в списке являются словарем, соответственно, когдаimage
иlabel
адрес данных.
Мыall_files
Пятикратная перекрестная проверка данных:
floder = KFold(n_splits=5, random_state=42, shuffle=True)
train_files = [] # 存放5折的训练集划分
test_files = [] # # 存放5折的测试集集划分
for k, (Trindex, Tsindex) in enumerate(floder.split(all_files)):
train_files.append(np.array(all_files)[Trindex].tolist())
test_files.append(np.array(all_files)[Tsindex].tolist())
# 把划分写入csv,检验每次是否相同
df = pd.DataFrame(data=train_files, index=['0', '1', '2', '3', '4'])
df.to_csv('./data/Kfold/train_patch.csv')
df1 = pd.DataFrame(data=test_files, index=['0', '1', '2', '3', '4'])
df1.to_csv('./data/Kfold/test_patch.csv')
Мы сохраняем раздел набора данных вcsv
Внутри, чтобы изменения кода не потеряли исходный метод деления.
После разделения набора данных его можно обучить и протестировать. Просто возьмите разделенные данные сгиба каждый раз.
# 五折分开train, 每次拿一折train 和 test
train(train_files[0], test_files[0])
test(test_files[0])
существуетtrain
иtest
В методе необходимо написать соответствующийdataloder
, потому что мы просто разделили имена данных, а не загружали набор данных.
Как обычно, цикл5
Во-вторых, запустите код один раз и сделайте на все результаты скидку 50%. Но преимущество нашего способа записи в том, что если вы хотите тренировать количество сгибов, просто измените значение индекса, и вам не нужно тренировать все сразу. Пока вы не переместите код и тренируетесь через год, разделение набора данных не изменится. Не бойтесь меняться, мы сохранили подразделение какcsv
.
Конечно, это всего лишь способ написать. Если есть лучшее решение, пожалуйста, оставьте сообщение для обсуждения~~
2. Нет проверочного набора, как сохранить лучшую модель
Это то, что меня интересовало раньше. Потому что, если я не делаю перекрестную проверку, я сохраняю лучшую модель на основе метрик в тестовом наборе. Например, следующий код выполняется для набора проверки.
if metric > best_metric:
best_metric = metric
best_metric_epoch = epoch + 1
save_dir = 'checkpoints/checkpoint_04264/'
if not os.path.exists(save_dir):
os.makedirs(save_dir)
save_path = save_dir + str(epoch + 1) + "best_metric_model.pth"
torch.save(model.state_dict(), save_path)
print('saved new best metric model')
Но теперь нет проверочного набора, сохранить ли модель на основе метрик в обучающем наборе или сохранить модель на основе метрик в тестовом наборе? Единого ответа на этот вопрос нет, и используются оба подхода. Поскольку единого ответа нет, мы можем выбрать наиболее выгодный для нас ответ?. Например, при написании статьи сохранение модели на основе результатов тестового набора определенно даст лучшие результаты.
Также есть небольшаяtips
, результаты, полученные с перекрестной проверкой, обычно лучше, чем6:2:2
Разделите обучающий набор на проверочный набор, и результаты на тестовом наборе будут лучше. Подумай почему ?