Tensorflow против Tensorflow JS разные результаты для арифметических вычислений с плавающей запятой - PullRequest
1 голос
/ 18 июня 2019

Я преобразовал модель Tensorflow в Tensorflow JS и попытался использовать в браузере. Есть некоторые этапы предварительной обработки, которые должны быть выполнены на входе перед передачей его в модель для вывода. Я реализовал эти шаги так же, как Tensorflow. Проблема в том, что результаты логического вывода не совпадают на TF JS по сравнению с Tensorflow. Поэтому я начал отлаживать код и обнаружил, что результаты арифметических операций с плавающей запятой при предварительной обработке на TF JS отличаются от Tensorflow, который выполняется на контейнере Docker с графическим процессором. Код, используемый в TF JS, приведен ниже.

       var tensor3d = tf.tensor3d(image,[height,width,1],'float32')

        var pi= PI.toString();
        if(bs == 14 && pi.indexOf('1') != -1 ) {

          tensor3d =  tensor3d.sub(-9798.6993999999995).div(7104.607118190255)

        }
        else if(bs == 12 && pi.indexOf('1') != -1) {

          tensor3d = tensor3d.sub(-3384.9893000000002).div(1190.0708513300835)
        }
        else if(bs == 12 && pi.indexOf('2') != -1) {

          tensor3d =  tensor3d.sub(978.31200000000001).div(1092.2426342420442)

        }
        var resizedTensor = tensor3d.resizeNearestNeighbor([224,224]).toFloat()
        var copiedTens = tf.tile(resizedTensor,[1,1,3])
        return copiedTens.expandDims();

Используемые блоки кода Python

ds = pydicom.dcmread(input_filename, stop_before_pixels=True)
if (ds.BitsStored == 12) and '1' in ds.PhotometricInterpretation:
    normalize_mean = -3384.9893000000002
    normalize_std = 1190.0708513300835
elif (ds.BitsStored == 12) and '2' in ds.PhotometricInterpretation:
    normalize_mean = 978.31200000000001
    normalize_std = 1092.2426342420442
elif (ds.BitsStored == 14) and '1' in ds.PhotometricInterpretation:
    normalize_mean = -9798.6993999999995
    normalize_std = 7104.607118190255
else:
    error_response = "Unable to read required metadata, or metadata invalid. 
    BitsStored: {}. PhotometricInterpretation: {}".format(ds.BitsStored, 
    ds.PhotometricInterpretation)
    error_json = {'code': 500, 'message': error_response}
    self._set_headers(500)
    self.wfile.write(json.dumps(error_json).encode())
    return

    normalization = Normalization(mean=normalize_mean, std=normalize_std)
    resize = ResizeImage()
    copy_channels = CopyChannels()
    inference_data_collection.append_preprocessor([normalization, resize, 
    copy_channels])

Код нормализации

    def normalize(self, normalize_numpy, mask_numpy=None):

        normalize_numpy = normalize_numpy.astype(float)

        if mask_numpy is not None:
            mask = mask_numpy > 0
        elif self.mask_zeros:
            mask = np.nonzero(normalize_numpy)
        else:
            mask = None

        if mask is None:
            normalize_numpy = (normalize_numpy - self.mean) / self.std
        else:
            raise NotImplementedError

        return normalize_numpy

ResizeImage code

   from skimage.transform import resize

   def Resize(self, data_group):

        input_data = data_group.preprocessed_case

        output_data = resize(input_data, self.output_dim)

        data_group.preprocessed_case = output_data
        self.output_data = output_data

Код CopyChannels

    def CopyChannels(self, data_group):

        input_data = data_group.preprocessed_case

        if self.new_channel_dim:
            output_data = np.stack([input_data] * self.channel_multiplier, -1)
        else:
            output_data = np.tile(input_data, (1, 1, self.channel_multiplier))

        data_group.preprocessed_case = output_data
        self.output_data = output_data

Пример выходных данных Слева - Tensorflow на Docker с графическим процессором, а справа - TF JS: enter image description here

Результаты на самом деле отличаются после каждого шага.

1 Ответ

0 голосов
/ 19 июня 2019

Там может быть несколько возможностей, которые могут привести к этой проблеме.

1- Операции, используемые в python, не используются одинаково в js и python.Если это так, то использование одной и той же операции избавит вас от проблемы.

2 - изображение тензоров может быть прочитано библиотекой python и холстом браузера по-разному.На самом деле, в разных браузерах пиксель холста не всегда имеет одинаковое значение из-за некоторых операций, таких как сглаживание и т. Д., Как описано в этом ответе .Так что могут быть небольшие отличия в результате операций.Чтобы убедиться, что это является основной причиной проблемы, сначала попробуйте напечатать python и массив js image и посмотреть, одинаковы ли они.Вполне вероятно, что 3d-тензор отличается в js и python.

tensor3d = tf.tensor3d(image,[height,width,1],'float32')

В этом случае вместо непосредственного чтения изображения в браузере можно использовать библиотеку python для преобразования изображения в массив тензора.,И используйте tfjs для чтения непосредственно этого массива вместо изображения.Таким образом, входные тензоры будут одинаковыми как для js, так и для python.

3 - это проблема точности float32.тензор3d создается с dtype float32, и в зависимости от используемых операций может возникнуть проблема точности.Рассмотрим эту операцию:

tf.scalar(12045, 'int32').mul(tf.scalar(12045, 'int32')).print(); // 145082032 instead of 145082025

Та же проблема точности будет встречаться в python со следующим:

a = tf.constant([12045], dtype='float32') * tf.constant([12045], dtype='float32')
tf.print(a) // 145082032

В python это можно решить с помощью int32 dtype.Однако из-за ограничения webgl float32 то же самое нельзя сделать с помощью бэкэнда webgl на tfjs.В нейронных сетях эта проблема точности не имеет большого значения.Чтобы избавиться от него, можно изменить бэкэнд, например, с помощью setBackend('cpu'), что намного медленнее.

...