Interopérabilité Python

Voir sur TensorFlow.org Afficher la source sur GitHub

Swift For TensorFlow prend en charge l'interopérabilité Python.

Vous pouvez importer des modules Python depuis Swift, appeler des fonctions Python et convertir des valeurs entre Swift et Python.

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

Définition de la version Python

Par défaut, lorsque vous import Python , Swift recherche dans les chemins de bibliothèque système la dernière version de Python installée. Pour utiliser une installation Python spécifique, définissez la variable d'environnement PYTHON_LIBRARY sur la bibliothèque partagée libpython fournie par l'installation. Par exemple:

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

Le nom exact du fichier diffère selon les environnements et les plates-formes Python.

Vous pouvez également définir la variable d'environnement PYTHON_VERSION , qui demande à Swift de rechercher dans les chemins de la bibliothèque système une version Python correspondante. Notez que PYTHON_LIBRARY est prioritaire sur PYTHON_VERSION .

Dans le code, vous pouvez également appeler la fonction PythonLibrary.useVersion , ce qui équivaut à définir PYTHON_VERSION .

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

Remarque : vous devez exécuter PythonLibrary.useVersion juste après import Python , avant d'appeler du code Python. Il ne peut pas être utilisé pour changer dynamiquement de version de Python.

Définissez PYTHON_LOADER_LOGGING=1 pour voir la sortie de débogage pour le chargement de la bibliothèque Python .

Les bases

Dans Swift, PythonObject représente un objet de Python. Toutes les API Python utilisent et renvoient des instances PythonObject .

Les types de base dans Swift (comme les nombres et les tableaux) sont convertibles en PythonObject . Dans certains cas (pour les littéraux et les fonctions prenant des arguments PythonConvertible ), la conversion se produit implicitement. Pour convertir explicitement une valeur Swift en PythonObject , utilisez l'initialiseur PythonObject .

PythonObject définit de nombreuses opérations standard, notamment les opérations numériques, l'indexation et l'itération.

// 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 définit les conformités à de nombreux protocoles Swift standard :

  • Equatable
  • Comparable
  • Hashable
  • SignedNumeric
  • Strideable
  • MutableCollection
  • Tous les protocoles ExpressibleBy_Literal

Notez que ces conformités ne sont pas de type sécurisé : des plantages se produiront si vous tentez d'utiliser la fonctionnalité de protocole à partir d'une instance 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

Pour convertir des tuples de Python en Swift, vous devez connaître statiquement l'arité du tuple.

Appelez l'une des méthodes d'instance suivantes :

  • 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)

Intégrations Python

Accédez aux fonctions intégrées de Python via l'interface Python globale.

// `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

Importation de modules Python

Utilisez Python.import pour importer un module Python. Cela fonctionne comme le mot-clé 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.]]

Utilisez la fonction de lancement Python.attemptImport pour effectuer une importation sécurisée.

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

Conversion avec numpy.ndarray

Les types Swift suivants peuvent être convertis vers et depuis numpy.ndarray :

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

La conversion ne réussit que si le dtype de numpy.ndarray est compatible avec le type de paramètre générique Element ou Scalar .

Pour Array , la conversion depuis numpy ne réussit que si numpy.ndarray est 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.]

Affichage des images

Vous pouvez afficher des images en ligne à l'aide matplotlib , tout comme dans les notebooks 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.