Почему pytorch tensor.item() дает неточный вывод для любого ввода действительного числа, но дает точный вывод для числа, которое заканчивается на .0 или .5?

Вход:

x = torch.tensor([3.5])

print(x)
print(x.item())
print(float(x))

Выход: (tensor([3.5000]), 3.5, 3.5)

Но если я изменю параметр torch.tensor на любое другое значение, а не на some_value.5, результат будет неточным:

Вход:

x = torch.tensor([3.1])

print(x)
print(x.item())
print(float(x))

Выход: (tensor([3.1000]), 3.0999999046325684, 3.0999999046325684)

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
0
50
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Тензоры с плавающей запятой Pytorch по умолчанию имеют формат fp32. Плавающие числа Python — fp64. Числовая разница связана с преобразованием fp32 в fp64.

Вы можете изменить это, указав fp64 при создании тензора.

x = torch.tensor([3.1], dtype=torch.float64)

print(x)
> tensor([3.1000], dtype=torch.float64)
print(x.item())
> 3.1
print(float(x))
> 3.1
Ответ принят как подходящий

То, что вы испытываете, не имеет ничего общего с самим PyTorch, а скорее с представлением действительных чисел в виде значений с плавающей запятой на современном компьютере. Основная ситуация здесь следующая:

  1. Числа с плавающей запятой внутренне представляются по основанию 2 (другими словами, как двоичные числа) с фиксированным количеством бит.
  2. Точно так же, как дробь 1/3, которую невозможно точно представить фиксированным количеством цифр по основанию 10 (это 0,333…10 с бесконечным числом повторений цифры 3, где я использую …10 для обозначения основания число), дробная часть числа 3,1, равная 1/10, не может быть точно представлена ​​в системе счисления 2 (это 0,0001100110011…2 с бесконечным числом или повторениями последовательности 0011). Как вы заметили, это отличается от дробной части числа 3,5, равной 1/2, которую можно точно представить в системе счисления 2 (это 0,12).
  3. Имея только фиксированное количество доступных бит (см. 1), это означает, что дробь 1/10 может быть сохранена на компьютере только как приблизительное значение с плавающей запятой.

Это правда, что это исчезает, как только вы переключаетесь с 32-битных значений с плавающей запятой на 64-битные значения с плавающей запятой, как предложено в Ответе Карла, поскольку 64-битное значение с плавающей запятой имеет в два раза больше бит для представления. каждое значение. Однако это происходит не потому, что основная ситуация решена, а скорее потому, что ваш интерпретатор Python теперь в каком-то смысле знает, что он должен скрывать ситуацию от вас.

Попробуйте, например, напечатать f"{torch.tensor([3.1], dtype=torch.float64).item():.30f} или, по сути, f"{3.1:.30f}", тем самым заставив видеть больше цифр, чем Python по умолчанию хочет вам показать:

import torch

print(f"{torch.tensor([3.1], dtype=torch.float64).item():.30f}")
# >>> 3.100000000000000088817841970013
print(f"{3.1:.30f}")
# >>> 3.100000000000000088817841970013

Вы увидите, что и для 64-битного случая с плавающей запятой представление числа 3,1 с плавающей запятой является лишь приближением к истинному значению.

Аналогично, вы можете попробовать то же самое с версией 3.5 и обнаружите, что значение сохраняется точно:

import torch

print(f"{torch.tensor([3.5], dtype=torch.float64).item():.30f}")
# >>> 3.500000000000000000000000000000
print(f"{3.5:.30f}")
# >>> 3.500000000000000000000000000000

Следующее утверждение, вероятно, несколько смелое и, в зависимости от того, с какими данными вы работаете, огромное упрощение или даже просто неправильное, но все же: я бы сказал, что в повседневной жизни программиста вам редко приходится сталкиваться с этим. знания, но просто игнорируют тот факт, что значения с плавающей запятой в большинстве случаев являются лишь приближениями. Однако бывают ситуации, когда точная арифметика с плавающей запятой имеет значение, и для этого были разработаны такие решения, как модуль decimal и его Decimal класс.

Для получения дополнительной общей информации о свойствах арифметики с плавающей запятой вы можете просмотреть Арифметика с плавающей запятой: проблемы и ограничения из документации Python или несколько стандартную статью на эту тему Что Каждый компьютерный учёный должен знать об арифметике с плавающей запятой.

Другие вопросы по теме

Похожие вопросы

Рассчитать количество точек заданного радиуса по координатам X и Y
Почему некоторые функции регулярных выражений возвращают объект соответствия, а некоторые нет?
Группируйте элементы в фрейме данных и отображайте их в хронологическом порядке
Операции Pandas между типами с плавающей запятой и NaN
Используйте спецификатор формата для преобразования столбца float/int в фрейме данных Polars в строку
Как ВСТАВИТЬ в таблицу с помощью AUTO_INCREMENT?
Дилемма 100 заключенных: кодекс всегда приводит к провалу (все заключенные умирают)
Как устранить ошибку AttributeError: у модуля «Фиона» нет атрибута «Путь»?
Я работаю над тем, чтобы сделать бота Python, который будет нажимать кнопку в списке, который повторяется сам, используя селен
Какие замены регулярных выражений помогают при переписывании SQL-запросов MS Access как простых запросов TSQL? Как их можно зациклить с помощью Excel в качестве входных и выходных данных?