Interoperabilidad de Python

Ver en TensorFlow.org Ejecutar en Google Colab Ver fuente en GitHub

Swift For TensorFlow es compatible con la interoperabilidad de Python.

Puede importar módulos de Python desde Swift, llamar a funciones de Python y convertir valores entre Swift y Python.

import PythonKit
print(Python.version)
3.6.9 (default, Oct  8 2020, 12:12:24) 
[GCC 8.4.0]

Configuración de la versión de Python

De forma predeterminada, cuando import Python , Swift busca en las rutas de la biblioteca del sistema la versión más reciente de Python instalada. Para utilizar una instalación específica de Python, establezca la variable de entorno PYTHON_LIBRARY en la biblioteca compartida libpython proporcionada por la instalación. Por ejemplo:

export PYTHON_LIBRARY="~/anaconda3/lib/libpython3.7m.so"

El nombre de archivo exacto diferirá entre los entornos y plataformas de Python.

Alternativamente, puede configurar la variable de entorno PYTHON_VERSION , que le indica a Swift que busque rutas de la biblioteca del sistema para encontrar una versión de Python coincidente. Tenga en cuenta que PYTHON_LIBRARY tiene prioridad sobre PYTHON_VERSION .

En el código, también puede llamar a la función PythonLibrary.useVersion , que es equivalente a configurar PYTHON_VERSION .

// PythonLibrary.useVersion(2)
// PythonLibrary.useVersion(3, 7)

Nota: debe ejecutar PythonLibrary.useVersion justo después de import Python , antes de llamar a cualquier código de Python. No se puede usar para cambiar dinámicamente las versiones de Python.

Establezca PYTHON_LOADER_LOGGING=1 para ver la salida de depuración para la carga de la biblioteca de Python .

Lo esencial

En Swift, PythonObject representa un objeto de Python. Todas las API de Python usan y devuelven instancias PythonObject .

Los tipos básicos en Swift (como números y matrices) se pueden convertir a PythonObject . En algunos casos (para literales y funciones que toman argumentos PythonConvertible ), la conversión ocurre implícitamente. Para convertir explícitamente un valor Swift a PythonObject , use el inicializador PythonObject .

PythonObject define muchas operaciones estándar, incluidas operaciones numéricas, indexación e iteración.

// Convert standard Swift types to Python.
let pythonInt: PythonObject = 1
let pythonFloat: PythonObject = 3.0
let pythonString: PythonObject = "Hello Python!"
let pythonRange: PythonObject = PythonObject(5..<10)
let pythonArray: PythonObject = [1, 2, 3, 4]
let pythonDict: PythonObject = ["foo": [0], "bar": [1, 2, 3]]

// Perform standard operations on Python objects.
print(pythonInt + pythonFloat)
print(pythonString[0..<6])
print(pythonRange)
print(pythonArray[2])
print(pythonDict["bar"])
4.0
Hello 
slice(5, 10, None)
3
[1, 2, 3]

// Convert Python objects back to Swift.
let int = Int(pythonInt)!
let float = Float(pythonFloat)!
let string = String(pythonString)!
let range = Range<Int>(pythonRange)!
let array: [Int] = Array(pythonArray)!
let dict: [String: [Int]] = Dictionary(pythonDict)!

// Perform standard operations.
// Outputs are the same as Python!
print(Float(int) + float)
print(string.prefix(6))
print(range)
print(array[2])
print(dict["bar"]!)
4.0
Hello 
5..<10
3
[1, 2, 3]

PythonObject define la conformidad con muchos protocolos estándar de Swift:

  • Equatable
  • Comparable
  • Hashable
  • SignedNumeric
  • Strideable
  • MutableCollection
  • Todos los protocolos ExpressibleBy_Literal

Tenga en cuenta que estas conformidades no son de tipo seguro: se producirán bloqueos si intenta utilizar la funcionalidad del protocolo desde una instancia de PythonObject incompatible.

let one: PythonObject = 1
print(one == one)
print(one < one)
print(one + one)

let array: PythonObject = [1, 2, 3]
for (i, x) in array.enumerated() {
  print(i, x)
}
True
False
2
0 1
1 2
2 3

Para convertir tuplas de Python a Swift, debe conocer estáticamente la aridad de la tupla.

Llame a uno de los siguientes métodos de instancia:

  • PythonObject.tuple2
  • PythonObject.tuple3
  • PythonObject.tuple4
let pythonTuple = Python.tuple([1, 2, 3])
print(pythonTuple, Python.len(pythonTuple))

// Convert to Swift.
let tuple = pythonTuple.tuple3
print(tuple)
(1, 2, 3) 3
(1, 2, 3)

Componentes integrados de Python

Acceda a las funciones integradas de Python a través de la interfaz global de Python .

// `Python.builtins` is a dictionary of all Python builtins.
_ = Python.builtins

// Try some Python builtins.
print(Python.type(1))
print(Python.len([1, 2, 3]))
print(Python.sum([1, 2, 3]))
<class 'int'>
3
6

Importación de módulos de Python

Utilice Python.import para importar un módulo de Python. Funciona como la palabra clave de import en Python .

let np = Python.import("numpy")
print(np)
let zeros = np.ones([2, 3])
print(zeros)
<module 'numpy' from '/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/numpy/__init__.py'>
[[1. 1. 1.]
 [1. 1. 1.]]

Use la función de lanzamiento Python.attemptImport para realizar una importación segura.

let maybeModule = try? Python.attemptImport("nonexistent_module")
print(maybeModule)
nil

Conversión con numpy.ndarray

Los siguientes tipos de Swift se pueden convertir a y desde numpy.ndarray :

  • Array<Element>
  • ShapedArray<Scalar>
  • Tensor<Scalar>

La conversión solo tiene éxito si el numpy.ndarray dtype compatible con el tipo de parámetro genérico Element o Scalar .

Para Array , la conversión de numpy solo tiene éxito si numpy.ndarray es 1-D.

import TensorFlow

let numpyArray = np.ones([4], dtype: np.float32)
print("Swift type:", type(of: numpyArray))
print("Python type:", Python.type(numpyArray))
print(numpyArray.shape)
Swift type: PythonObject
Python type: <class 'numpy.ndarray'>
(4,)

// Examples of converting `numpy.ndarray` to Swift types.
let array: [Float] = Array(numpy: numpyArray)!
let shapedArray = ShapedArray<Float>(numpy: numpyArray)!
let tensor = Tensor<Float>(numpy: numpyArray)!

// Examples of converting Swift types to `numpy.ndarray`.
print(array.makeNumpyArray())
print(shapedArray.makeNumpyArray())
print(tensor.makeNumpyArray())

// Examples with different dtypes.
let doubleArray: [Double] = Array(numpy: np.ones([3], dtype: np.float))!
let intTensor = Tensor<Int32>(numpy: np.ones([2, 3], dtype: np.int32))!
[1. 1. 1. 1.]
[1. 1. 1. 1.]
[1. 1. 1. 1.]

Visualización de imágenes

Puede mostrar imágenes en línea usando matplotlib , al igual que en los cuadernos de Python.

// This cell is here to display plots inside a Jupyter Notebook.
// Do not copy it into another environment.
%include "EnableIPythonDisplay.swift"
print(IPythonDisplay.shell.enable_matplotlib("inline"))
('inline', 'module://ipykernel.pylab.backend_inline')

let np = Python.import("numpy")
let plt = Python.import("matplotlib.pyplot")

let time = np.arange(0, 10, 0.01)
let amplitude = np.exp(-0.1 * time)
let position = amplitude * np.sin(3 * time)

plt.figure(figsize: [15, 10])

plt.plot(time, position)
plt.plot(time, amplitude)
plt.plot(time, -amplitude)

plt.xlabel("Time (s)")
plt.ylabel("Position (m)")
plt.title("Oscillations")

plt.show()

png

Use `print()` to show values.