如何 "standardize" 具有可变长度的数据集?
How to "standardize" a dataset that has a variable length?
我不确定我的问题措辞是否正确,但要点如下:
我正在使用的数据集 SVC 2004 有 x 个文件,每个文件都有 y 个 7 元组,因此数据集的形状变为 (x, y, 7)。我已经对数据进行了归一化处理,并将其插入一维 CNN 进行特征提取,并将 RNN 作为分类器。但问题是:y 对于每个文件 都不相同。这在创建 Sequential 模型时会导致问题,因为它需要恒定的形状。这是我的一些代码:
//DataPreprocessing
def load_dataset_normalized(path):
file_names = os.listdir(path)
num_of_persons = len(file_names)
initial_starting_point = np.zeros(np.shape([7]))
highest_num_of_points = find_largest_num_of_points(path)
x_dataset = []
y_dataset = []
current_file = 0
for infile in file_names:
full_file_name = os.path.join(path, infile)
file = open(full_file_name, "r")
file_lines = file.readlines()
num_of_points = int(file_lines[0])
x = []
y = []
time_stamp = []
button_status = []
azimuth_angles = []
altitude = []
pressure = []
for idx, line in enumerate(file_lines[1:]):
idx+=1
nums = line.split(' ')
if idx == 1:
nums[2] = 0
initial_starting_point = nums
x.append(float(nums[0]))
y.append(float(nums[1]))
time_stamp.append(0.0)
button_status.append(float(nums[3]))
azimuth_angles.append(float(nums[4]))
altitude.append(float(nums[5]))
pressure.append(float(nums[6]))
else:
x.append(float(nums[0]))
y.append(float(nums[1]))
time_stamp.append(10)
button_status.append(float(nums[3]))
azimuth_angles.append(float(nums[4]))
altitude.append(float(nums[5]))
pressure.append(float(nums[6]))
max_x = max(x)
max_y = max(y)
max_azimuth_angle = max(azimuth_angles)
max_altitude = max(altitude)
max_pressure = max(pressure)
min_x = min(x)
min_y = min(y)
min_azimuth_angle = min(azimuth_angles)
min_altitude = min(altitude)
min_pressure = min(pressure)
#Alignment normalization:
for i in range(num_of_points):
x[i] -= float(initial_starting_point[0])
y[i] -= float(initial_starting_point[1])
azimuth_angles[i] -= float(initial_starting_point[4])
altitude[i] -= float(initial_starting_point[5])
pressure[i] -= float(initial_starting_point[6])
#Size normalization
for i in range(num_of_points):
x[i] = ((x[i] - max_x) / (min_x - max_x))
y[i] = ((y[i] - max_y) / (min_y - max_y))
azimuth_angles[i] = ((azimuth_angles[i] - max_azimuth_angle) / (min_azimuth_angle - max_azimuth_angle))
altitude[i] = ((altitude[i] - max_altitude) / (min_altitude - max_altitude))
pressure[i] = ((pressure[i] - max_pressure) / (min_pressure - max_pressure))
#data points to dataset
x_line = []
for i in range (num_of_points):
x_line.append(([x[i], y[i], time_stamp[i], button_status[i], azimuth_angles[i], altitude[i], pressure[i]]))
if (num_of_points < 713) and (i == num_of_points-1):
for idx in range(713 - num_of_points):
x_line.append([0, 0, 0, 0, 0, 0, 0])
if i == num_of_points-1:
x_dataset.append(x_line)
current_file += 1
infile_without_extension = infile.replace('.TXT','')
index_of_s = infile_without_extension.find("S")
index_of_num = index_of_s + 1
sig_ID = int(infile_without_extension[index_of_num:])
if sig_ID < 21:
y_dataset.append([1,0])
else:
y_dataset.append([0,1])
x_dataset = np.array([np.array(xi) for xi in x_dataset])
y_dataset = np.asarray(y_dataset)
return x_dataset, y_dataset, highest_num_of_points
//Class that creates my model (creation of model works perfectly)
class crnn_model:
def build_model(self, input_shape_num, x_train, y_train, x_test, y_test):
model = Sequential()
model.add(Conv1D(filters=50, kernel_size=3, activation='sigmoid', input_shape = (713, 7)))
model.add(MaxPooling1D(pool_size=3))
model.add(LSTM(2))
model.compile(optimizer='adam', loss='mse', metrics = ['accuracy'])
model.summary()
print(model.fit(x_train, y_train, epochs=50, verbose=0))
yhat = model.predict(x_test, verbose=0)
print(yhat)
我已经考虑过使用具有最多 7 元组的文件作为形状,因为我现在已经硬编码了上面的代码 (713)。这是一个好的选择吗?如果不是,我该如何处理 "standardizing" 或 "normalizing" CNN 输入形状的点数 (y)?
根据我的经验,人们倾向于选择任意长度。任何较短的序列都会被填充(通常用零),任何较长的序列都会被截断。
您选择的长度取决于数据集;通常我会制作一个长度直方图,然后观察一个保留大部分数据而没有太多不必要填充的数字。通常这就在第 90-95 个百分位左右。但是,如果最长长度不比平均长度长太多(例如,它小于两倍),那么将其设为这个数字也不是不合理的。
另一个可能的选项——虽然我没有这方面的经验因此不能推荐它——只是对每个批次进行标准化。任何给定批次的所有样本都需要具有相同的长度,但独立的批次可以具有不同的长度。理论上,您可以根据序列长度对数据进行分区,然后使用尽可能少的 padding/truncating 进行批处理。然而,这可能需要付出很多努力,并且只有在序列长度与其他任何事物都不相关的情况下才可能奏效。我建议不要尝试这种方法。
这里你指的是可变长度序列,你可以通过让 input_shape=(None, 7)
来实现。这表示每个批次 y
可能会有所不同 但不会在一个批次 内发生变化。所以我们通过以下方式解决这个问题:
- 实施 Sequence that takes the data and chops into batches. For each batch it returns
(batch_size, y_max_within_batch, 7)
by padding using pad_sequences.
- 设置
input_shape=(None, 7)
以便您的模型在运行时可以使用不同长度的输入。这表示我将在每批中使用许多 7 元组。
- 可选择使用 Masking Layer 来屏蔽填充序列,这样您的模型就不会将填充用作特征,而只会预测样本的正确长度。您还可以预测填充,这将使预测更容易考虑序列的长度。
这些主要是您在 Keras 中处理不同长度序列所需的工具/层。如何使用它们以及填充的效果等取决于您要解决的任务。
我不确定我的问题措辞是否正确,但要点如下: 我正在使用的数据集 SVC 2004 有 x 个文件,每个文件都有 y 个 7 元组,因此数据集的形状变为 (x, y, 7)。我已经对数据进行了归一化处理,并将其插入一维 CNN 进行特征提取,并将 RNN 作为分类器。但问题是:y 对于每个文件 都不相同。这在创建 Sequential 模型时会导致问题,因为它需要恒定的形状。这是我的一些代码:
//DataPreprocessing
def load_dataset_normalized(path):
file_names = os.listdir(path)
num_of_persons = len(file_names)
initial_starting_point = np.zeros(np.shape([7]))
highest_num_of_points = find_largest_num_of_points(path)
x_dataset = []
y_dataset = []
current_file = 0
for infile in file_names:
full_file_name = os.path.join(path, infile)
file = open(full_file_name, "r")
file_lines = file.readlines()
num_of_points = int(file_lines[0])
x = []
y = []
time_stamp = []
button_status = []
azimuth_angles = []
altitude = []
pressure = []
for idx, line in enumerate(file_lines[1:]):
idx+=1
nums = line.split(' ')
if idx == 1:
nums[2] = 0
initial_starting_point = nums
x.append(float(nums[0]))
y.append(float(nums[1]))
time_stamp.append(0.0)
button_status.append(float(nums[3]))
azimuth_angles.append(float(nums[4]))
altitude.append(float(nums[5]))
pressure.append(float(nums[6]))
else:
x.append(float(nums[0]))
y.append(float(nums[1]))
time_stamp.append(10)
button_status.append(float(nums[3]))
azimuth_angles.append(float(nums[4]))
altitude.append(float(nums[5]))
pressure.append(float(nums[6]))
max_x = max(x)
max_y = max(y)
max_azimuth_angle = max(azimuth_angles)
max_altitude = max(altitude)
max_pressure = max(pressure)
min_x = min(x)
min_y = min(y)
min_azimuth_angle = min(azimuth_angles)
min_altitude = min(altitude)
min_pressure = min(pressure)
#Alignment normalization:
for i in range(num_of_points):
x[i] -= float(initial_starting_point[0])
y[i] -= float(initial_starting_point[1])
azimuth_angles[i] -= float(initial_starting_point[4])
altitude[i] -= float(initial_starting_point[5])
pressure[i] -= float(initial_starting_point[6])
#Size normalization
for i in range(num_of_points):
x[i] = ((x[i] - max_x) / (min_x - max_x))
y[i] = ((y[i] - max_y) / (min_y - max_y))
azimuth_angles[i] = ((azimuth_angles[i] - max_azimuth_angle) / (min_azimuth_angle - max_azimuth_angle))
altitude[i] = ((altitude[i] - max_altitude) / (min_altitude - max_altitude))
pressure[i] = ((pressure[i] - max_pressure) / (min_pressure - max_pressure))
#data points to dataset
x_line = []
for i in range (num_of_points):
x_line.append(([x[i], y[i], time_stamp[i], button_status[i], azimuth_angles[i], altitude[i], pressure[i]]))
if (num_of_points < 713) and (i == num_of_points-1):
for idx in range(713 - num_of_points):
x_line.append([0, 0, 0, 0, 0, 0, 0])
if i == num_of_points-1:
x_dataset.append(x_line)
current_file += 1
infile_without_extension = infile.replace('.TXT','')
index_of_s = infile_without_extension.find("S")
index_of_num = index_of_s + 1
sig_ID = int(infile_without_extension[index_of_num:])
if sig_ID < 21:
y_dataset.append([1,0])
else:
y_dataset.append([0,1])
x_dataset = np.array([np.array(xi) for xi in x_dataset])
y_dataset = np.asarray(y_dataset)
return x_dataset, y_dataset, highest_num_of_points
//Class that creates my model (creation of model works perfectly)
class crnn_model:
def build_model(self, input_shape_num, x_train, y_train, x_test, y_test):
model = Sequential()
model.add(Conv1D(filters=50, kernel_size=3, activation='sigmoid', input_shape = (713, 7)))
model.add(MaxPooling1D(pool_size=3))
model.add(LSTM(2))
model.compile(optimizer='adam', loss='mse', metrics = ['accuracy'])
model.summary()
print(model.fit(x_train, y_train, epochs=50, verbose=0))
yhat = model.predict(x_test, verbose=0)
print(yhat)
我已经考虑过使用具有最多 7 元组的文件作为形状,因为我现在已经硬编码了上面的代码 (713)。这是一个好的选择吗?如果不是,我该如何处理 "standardizing" 或 "normalizing" CNN 输入形状的点数 (y)?
根据我的经验,人们倾向于选择任意长度。任何较短的序列都会被填充(通常用零),任何较长的序列都会被截断。
您选择的长度取决于数据集;通常我会制作一个长度直方图,然后观察一个保留大部分数据而没有太多不必要填充的数字。通常这就在第 90-95 个百分位左右。但是,如果最长长度不比平均长度长太多(例如,它小于两倍),那么将其设为这个数字也不是不合理的。
另一个可能的选项——虽然我没有这方面的经验因此不能推荐它——只是对每个批次进行标准化。任何给定批次的所有样本都需要具有相同的长度,但独立的批次可以具有不同的长度。理论上,您可以根据序列长度对数据进行分区,然后使用尽可能少的 padding/truncating 进行批处理。然而,这可能需要付出很多努力,并且只有在序列长度与其他任何事物都不相关的情况下才可能奏效。我建议不要尝试这种方法。
这里你指的是可变长度序列,你可以通过让 input_shape=(None, 7)
来实现。这表示每个批次 y
可能会有所不同 但不会在一个批次 内发生变化。所以我们通过以下方式解决这个问题:
- 实施 Sequence that takes the data and chops into batches. For each batch it returns
(batch_size, y_max_within_batch, 7)
by padding using pad_sequences. - 设置
input_shape=(None, 7)
以便您的模型在运行时可以使用不同长度的输入。这表示我将在每批中使用许多 7 元组。 - 可选择使用 Masking Layer 来屏蔽填充序列,这样您的模型就不会将填充用作特征,而只会预测样本的正确长度。您还可以预测填充,这将使预测更容易考虑序列的长度。
这些主要是您在 Keras 中处理不同长度序列所需的工具/层。如何使用它们以及填充的效果等取决于您要解决的任务。