【问题标题】:How to "standardize" a dataset that has a variable length?如何“标准化”具有可变长度的数据集?
【发布时间】:2019-09-17 18:49:05
【问题描述】:

我不确定我的问题措辞是否正确,但要点如下: 我正在使用的数据集 SVC 2004 有 x 个文件,每个文件有 y 个 7 元组,因此数据集的形状变为 (x, y, 7)。我已经对数据进行了规范化,并将其插入到 1D CNN 中以进行特征提取,并将 RNN 作为分类器。但问题是:每个文件的 y 都不相同。这在创建顺序模型时会导致问题,因为它需要一个恒定的形状。这是我的一些代码:

//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) 进行了硬编码。这会是一个很好的选择吗?如果不是,我该如何“标准化”或“标准化”CNN输入形状的点数(y)?

【问题讨论】:

    标签: python keras conv-neural-network recurrent-neural-network


    【解决方案1】:

    在这里,您指的是可变长度序列,您可以通过让input_shape=(None, 7) 来实现。这表示每个批次的y 可能会有所不同但不会在批次内。所以我们通过以下方式解决这个问题:

    • 实现一个Sequence 来获取数据并分批。对于每个批次,它通过 padding 使用 pad_sequences 返回 (batch_size, y_max_within_batch, 7)
    • 设置input_shape=(None, 7) 以便在运行时您的模型可以使用不同长度的输入。这表示我将在每批中使用许多 7 元组。
    • 可以选择使用Masking Layer 屏蔽填充序列,这样您的模型就不会使用填充作为特征,而只会预测正确的样本长度。您还可以预测填充,这将使预测更容易考虑到序列的长度。

    这些主要是您在 Keras 中处理不同长度序列所需的工具/层。您如何使用它们以及填充等效果取决于您要解决的任务。

    【讨论】:

    • 感谢您的反馈。但是,pad_sequences 到底应该去哪里?在数据预处理中还是在哪里建模型?
    • 在 Sequence 对象中,您可以在其中创建批次。
    • 我没有创建任何批次。我已经将代码添加到我的预处理中,到目前为止似乎没有问题。我目前正在运行 1000 个 epoch 的测试,但从第一个 epoch 到当前 200 个 epoch 的准确度从未改变。
    【解决方案2】:

    根据我的经验,人们倾向于选择任意长度。任何较短的序列都会被填充(通常用零),而任何较长的序列都会被截断。

    您选择的长度取决于数据集;通常我会制作一个长度的直方图,然后观察一个数字,该数字可以保留大部分数据而没有太多不必要的填充。这通常在第 90-95 个百分位左右。但是,如果最长长度不比平均长度长太多(例如,它小于两倍),那么将这个数字设为这个数字并不是不合理的。


    另一个可能选项——虽然我没有这方面的经验,因此不推荐它——只是对每个批次进行标准化。任何给定批次的所有样本都需要具有相同的长度,但独立批次可以具有不同的长度。从理论上讲,您可以根据序列长度对数据进行分区,然后使用尽可能少的填充/截断进行批处理。但是,这可能需要付出很多努力,并且可能仅在序列长度与其他任何内容不相关的情况下才有效。我建议不要尝试这种方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 2011-07-17
      • 1970-01-01
      • 1970-01-01
      • 2019-10-22
      • 2014-02-10
      • 1970-01-01
      相关资源
      最近更新 更多