Enero de 2019
Volumen 34, número 1
[Aprendizaje automático]
Introducción a PyTorch en Windows
Por James McCaffrey
Aunque es bastante difícil, es posible crear redes neuronales a partir de código sin procesar. Por suerte, existen muchas bibliotecas de código abierto que puede usar para acelerar el proceso. Entre estas bibliotecas se incluye CNTK (Microsoft), TensorFlow (Google) y scikit-learn. La mayor parte de estas bibliotecas de redes neuronales están escritas en C++ por motivos de rendimiento, pero cuentan con una API de Python para su comodidad.
En este artículo mostraré cómo empezar a trabajar con la biblioteca popular de PyTorch. En comparación con muchas otras bibliotecas de redes neuronales, PyTorch opera en un nivel inferior de abstracción. Esto le ofrece más control sobre su código y le permite una personalización más simplificada, a costa de tener que escribir código adicional.
La mejor manera de ver hacia dónde se dirige este artículo es echar un vistazo al programa de demostración de la Figura 1. El programa de demostración lee el conjunto de datos de Iris conocido en la memoria. El objetivo consiste en predecir las especies de una flor Iris (setosa, versicolor o virginica) a partir de cuatro valores de predicción: longitud y el ancho del sépalo y la longitud y el ancho del pétalo. Un sépalo es una estructura similar a una hoja.
Figura 1 Ejemplo de un conjunto de datos Iris mediante PyTorch
El conjunto de datos Iris completo tiene 150 elementos. El programa de demostración usa 120 elementos para el aprendizaje y 30 para realizar pruebas. Primero, la demostración crea una red neuronal con PyTorch y, luego, entrena la red con 600 iteraciones. Después del aprendizaje, el modelo se evalúa con los datos de prueba. El modelo entrenado tiene una precisión de un 90,00 por ciento, lo que significa que el modelo predice correctamente las especies de 27 de 30 elementos de prueba.
La demostración finaliza al predecir las especies de una flor Iris nueva no vista anteriormente que tiene los valores de sépalo y pétalo (6.1, 3.1, 5.1 y 1.1). Las probabilidades de predicción son (0,0454, 0,6798, 0,2748), las cuales se asignan a una predicción de versicolor.
En este artículo se supone que tiene conocimientos intermedios o altos de programación con un lenguaje de la familia C, pero no que no sepa nada acerca de PyTorch. En este artículo se presenta el código de demostración completo. El código fuente y los dos archivos de datos que usa la demostración también están disponible en la descarga que acompaña este artículo. Se han eliminado todas las comprobaciones de errores normales para mantener las ideas principales lo más claro posible.
Instalar PyTorch
La instalación de PyTorch implica dos pasos. Primero, debe instalar Python y varios paquetes auxiliares necesarios, como NumPy y SciPy, y, luego, debe instalar PyTorch como un paquete de complementos. Aunque es posible instalar Python y los paquetes necesarios para ejecutar PyTorch por separado, es mucho mejor instalar una distribución de Python. Le recomiendo encarecidamente usar la distribución Anaconda de Python, que cuenta con todos los paquetes que necesita para ejecutar PyTorch, además de muchos otros paquetes útiles. En este artículo, abordo la instalación en una máquina Windows 10. La instalación en macOS y los sistemas Linux es similar.
Coordinar las versiones compatibles de Python, los paquetes auxiliares requeridos y PyTorch es un desafío no trivial. Casi todos los errores de instalación que he visto están relacionados con incompatibilidades entre versiones. En el momento en que escribo este artículo, utilizo Ananconda3 5.2.0 (que contiene Python 3.6.5, 1.14.3 NumPy y SciPy 1.1.0) y PyTorch 0.4.1. Estas versiones son bastante estables, pero, dado que PyTorch es relativamente nuevo y se encuentra en desarrollo continuo, es posible que en el momento en que lea este artículo haya disponible una versión más reciente.
Antes de comenzar, le recomiendo desinstalar cualquier sistema de Python que tenga en su máquina, mediante el Panel de control de Windows | Programas y características. También le sugiero que cree un directorio C:\PyTorch para contener los archivos de instalación y de proyecto (código y datos).
Para instalar la distribución de Anaconda, vaya a repo.continuum.io/archive y busque el archivo Anaconda3-5.2.0-Windows-x86_64.exe, que es un ejecutable autoextraíble. Si hace clic en el vínculo, obtendrá un cuadro de diálogo con botones para ejecutar o guardar. Puede hacer clic en el botón Ejecutar.
El instalador de Anaconda es muy fácil de usar. Se le mostrará un conjunto de ocho pantallas del asistente para instalación. Puede aceptar todos los valores predeterminados y simplemente hacer clic en el botón Siguiente en cada pantalla, con una excepción. Cuando llegue a la pantalla en que se le pide si quiere agregar Python a la variable de entorno PATH del sistema, el valor predeterminado está desactivado (no). Le recomiendo activar esa opción para no tener que editar manualmente su PATH del sistema. La configuración predeterminada colocará el intérprete de Python y más de 500 paquetes compatibles en el directorio C:\Users\<usuario>\AppData\Local\ Continuum\Anaconda3 directory.
Para instalar la biblioteca de PyTorch, vaya a pytorch.org y busque el vínculo "Previous versions of PyTorch" ("Versiones anteriores de PyTorch") y haga clic en él. Busque un archivo denominado torch-0.4.1-cp36-cp36m-win_amd64.whl. Se trata de un archivo de Python "wheel". Puede considerar que un archivo .whl es algo similar a un archivo .msi de Windows. Si hace clic en el vínculo, obtendrá una opción para abrir o guardar. Elija Guardar como y coloque el archivo .whl en su directorio C:\PyTorch. Si no puede localizar el archivo .whl de PyTorch, inténtelo buscar en bit.ly/2SUiAuj, que es donde estaba cuando escribí este artículo.
Puede instalar PyTorch mediante la utilidad PIP de Python, que obtiene con la distribución de Anaconda. Abra un shell de comandos de Windows y desplácese al directorio donde guardó el archivo .whl de PyTorch. A continuación, escriba el comando siguiente:
C:\PyTorch> pip install torch-0.4.1-cp36-cp36m-win_amd64.whl
La instalación es rápida, pero hay muchas cosas que pueden ir mal. Si se produce un error en la instalación, lea detenidamente los mensajes de error en el shell. Probablemente, el problema será debido a la compatibilidad de versiones.
Para verificar que Python y PyTorch se han instalado correctamente, abra un shell de comandos y escriba "python" para iniciar el intérprete de Python. Verá el símbolo del sistema ">>>" de Python. A continuación, escriba los comandos siguientes (observe que hay dos caracteres de subrayado consecutivos en el comando de versión):
C:\>python
>>> import torch as T
>>> T.__version__
'0.4.1'
>>> exit()
C:\>
Si ve que las respuestas se muestran aquí, enhorabuena, significa que está listo para empezar a escribir código de aprendizaje automático de redes neuronales mediante PyTorch.
Preparar el conjunto de datos de Iris
Encontrará el conjunto de datos de Iris sin procesar en bit.ly/1N5br3h. Los datos tienen el aspecto siguiente:
5.1, 3.5, 1.4, 0.2, Iris-setosa
4.9, 3.0, 1.4, 0.2, Iris-setosa
...
7.0, 3.2, 4.7, 1.4, Iris-versicolor
6.4, 3.2, 4.5, 1.5, Iris-versicolor
...
6.2, 3.4, 5.4, 2.3, Iris-virginica
5.9, 3.0, 5.1, 1.8, Iris-virginica
Los primeros cuatro valores de cada línea son la longitud y el ancho del sépalo y la longitud y el ancho del pétalo de una flor. El quinto elemento son las especie que se predecirán. Los datos sin procesar tienen 50 setosa, seguidos de 50 versicolor, seguidos de 50 virginica. El archivo de aprendizaje son los primeros 40 de cada especie (120 elementos), y el archivo de prueba son los últimos 10 de cada especie (30 elementos). Dado que existen siete variables de predicción, no es viable elaborar un gráfico del conjunto de datos. No obstante, puede hacerse una idea de la estructura de los datos examinando el gráfico de la Figura 2.
Figura 2 Datos parciales de Iris
Las redes neuronales solo comprenden los números, por lo que las especies deben estar codificadas. Con la mayoría de las bibliotecas de redes neuronales, reemplazaría setosa por (1, 0, 0), versicolor por (0, 1, 0) y virginica por (0, 0, 1). Esto se denomina codificación 1-de-N o "one-hot". Sin embargo, PyTorch realiza una codificación "one-hot" en segundo plano y espera 0, 1 o 2 para las tres clases. Por lo tanto, los datos codificados de PyTorch tienen un aspecto similar al siguiente:
5.1, 3.5, 1.4, 0.2, 0
4.9, 3.0, 1.4, 0.2, 0
...
7.0, 3.2, 4.7, 1.4, 1
6.4, 3.2, 4.5, 1.5, 1
...
6.2, 3.4, 5.4, 2.3, 2
5.9, 3.0, 5.1, 1.8, 2
En la mayoría de los casos, debe normalizar las variables de predicción, normalmente mediante el escalado a fin de que todos los valores estén comprendidos entre 0,0 y 1,0, con lo que se denomina normalización mínima-máxima. No normalicé los datos de Iris con la finalidad de mantener la demostración un poco más simple. Al trabajar con redes neuronales, normalmente creo una carpeta raíz para el problema, como C:\PyTorch\Iris, y, a continuación, un subdirectorio denominado Data para almacenar los archivos de datos.
Programa de demostración
El programa de demostración completo, con ediciones menores para ahorrar espacio, se presenta en la Figura 3. Para ahorrar espacio, aplico una sangría de dos espacios en lugar de los cuatro espacios habituales. Usé el Bloc de notas para editar el programa de demostración, pero existen docenas de editores de Python que cuentan con funciones avanzadas. Tenga en cuenta que Python utiliza el carácter "\" para la continuación de línea.
Figura 3 Programa de demostración del conjunto de datos de Iris
# iris_nn.py
# PyTorch 0.4.1 Anaconda3 5.2.0 (Python 3.6.5)
import numpy as np
import torch as T
# -----------------------------------------------------------
class Batch:
def __init__(self, num_items, bat_size, seed=0):
self.num_items = num_items; self.bat_size = bat_size
self.rnd = np.random.RandomState(seed)
def next_batch(self):
return self.rnd.choice(self.num_items, self.bat_size,
replace=False)
# -----------------------------------------------------------
class Net(T.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = T.nn.Linear(4, 7)
T.nn.init.xavier_uniform_(self.fc1.weight) # glorot
T.nn.init.zeros_(self.fc1.bias)
self.fc2 = T.nn.Linear(7, 3)
T.nn.init.xavier_uniform_(self.fc2.weight)
T.nn.init.zeros_(self.fc2.bias)
def forward(self, x):
z = T.tanh(self.fc1(x))
z = self.fc2(z) # see CrossEntropyLoss() below
return z
# -----------------------------------------------------------
def accuracy(model, data_x, data_y):
X = T.Tensor(data_x)
Y = T.LongTensor(data_y)
oupt = model(X)
(_, arg_maxs) = T.max(oupt.data, dim=1)
num_correct = T.sum(Y==arg_maxs)
acc = (num_correct * 100.0 / len(data_y))
return acc.item()
# -----------------------------------------------------------
def main():
# 0. get started
print("\nBegin Iris Dataset with PyTorch demo \n")
T.manual_seed(1); np.random.seed(1)
# 1. load data
print("Loading Iris data into memory \n")
train_file = ".\\Data\\iris_train.txt"
test_file = ".\\Data\\iris_test.txt"
train_x = np.loadtxt(train_file, usecols=range(0,4),
delimiter=",", skiprows=0, dtype=np.float32)
train_y = np.loadtxt(train_file, usecols=[4],
delimiter=",", skiprows=0, dtype=np.float32)
test_x = np.loadtxt(test_file, usecols=range(0,4),
delimiter=",", skiprows=0, dtype=np.float32)
test_y = np.loadtxt(test_file, usecols=[4],
delimiter=",", skiprows=0, dtype=np.float32)
# 2. define model
net = Net()
# -----------------------------------------------------------
# 3. train model
net = net.train() # set training mode
lrn_rate = 0.01; b_size = 12
max_i = 600; n_items = len(train_x)
loss_func = T.nn.CrossEntropyLoss() # applies softmax()
optimizer = T.optim.SGD(net.parameters(), lr=lrn_rate)
batcher = Batch(num_items=n_items, bat_size=b_size)
print("Starting training")
for i in range(0, max_i):
if i > 0 and i % (max_i/10) == 0:
print("iteration = %4d" % i, end="")
print(" loss = %7.4f" % loss_obj.item(), end="")
acc = accuracy(net, train_x, train_y)
print(" accuracy = %0.2f%%" % acc)
curr_bat = batcher.next_batch()
X = T.Tensor(train_x[curr_bat])
Y = T.LongTensor(train_y[curr_bat])
optimizer.zero_grad()
oupt = net(X)
loss_obj = loss_func(oupt, Y)
loss_obj.backward()
optimizer.step()
print("Training complete \n")
# 4. evaluate model
net = net.eval() # set eval mode
acc = accuracy(net, test_x, test_y)
print("Accuracy on test data = %0.2f%%" % acc)
# 5. save model
# TODO
# -----------------------------------------------------------
# 6. make a prediction
unk = np.array([[6.1, 3.1, 5.1, 1.1]], dtype=np.float32)
unk = T.tensor(unk) # to Tensor
logits = net(unk) # values do not sum to 1.0
probs_t = T.softmax(logits, dim=1) # as Tensor
probs = probs_t.detach().numpy() # to numpy array
print("\nSetting inputs to:")
for x in unk[0]: print("%0.1f " % x, end="")
print("\nPredicted: (setosa, versicolor, virginica)")
for p in probs[0]: print("%0.4f " % p, end="")
print("\n\nEnd Iris demo")
if __name__ == "__main__":
main()
La estructura de un programa de PyTorch difiere ligeramente de la de otras bibliotecas. En la demostración, la clase Batch definida por el programa ofrece un número específico de elementos para el aprendizaje. La clase Net define la red neuronal 4-7-3. La precisión de la función calcula la precisión de la clasificación (porcentaje de predicciones correctas) de los datos mediante un modelo o red específicos. Toda la lógica de control se incluye en una sola función main.
Dado que PyTorch y Python se están desarrollando tan rápido , debe incluir un comentario que indique qué versiones se usan. Muchos programadores que son nuevos en Python se sorprenden al descubrir que Python base no es compatible con matrices. PyTorch utiliza las matrices de NumPy, por lo que casi siempre deberá importar el paquete NumPy.
Definir la red neuronal
La definición de la red neuronal comienza con lo siguiente:
class Net(T.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = T.nn.Linear(4, 7)
T.nn.init.xavier_uniform_(self.fc1.weight)
T.nn.init.zeros_(self.fc1.bias)
...
La primera línea de código indica que la clase se hereda de una clase T.nn.Module, que contiene funciones para crear una red neuronal. La función __init__ se puede considerar como un constructor de la clase. El objeto fc1 ("capa 1 completamente conectada") es la capa oculta de la red, que espera cuatro valores de entrada (los valores de predicción) y tiene siete nodos de procesamiento. La cantidad de nodos ocultos es un hiperparámetro y debe definirse mediante prueba y error. Las ponderaciones de la capa oculta se inicializan mediante el algoritmo Xavier uniform, que se denomina Glorot uniform en la mayoría de las otra bibliotecas. Los sesgos de la capa oculta se inicializan en cero.
La capa de salida de red se define mediante:
self.fc2 = T.nn.Linear(7, 3)
T.nn.init.xavier_uniform_(self.fc2.weight)
T.nn.init.zeros_(self.fc2.bias)
La capa de salida espera siete entradas (de la capa oculta) y genera tres valores de salida, uno para cada especie posible. Tenga en cuenta que lógicamente las capas de salida y oculta no están conectadas en este momento. La conexión se establece mediante la función forward necesaria siguiente:
def forward(self, x):
z = T.tanh(self.fc1(x))
z = self.fc2(z) # no softmax!
return z
La función acepta x, que es son los valores de predicción de entrada. Estos valores se pasan a la capa oculta y, a continuación, los resultados se pasan a la función de activación tanh. Ese resultado se pasa a la capa de salida y se devuelven los resultados finales. A diferencia de muchas bibliotecas de redes neuronales, con PyTorch no debe aplicar la activación de softmax para la capa de salida porque la función de pérdida de aprendizaje aplicará automáticamente softmax. Si aplicara softmax en la capa de salida, la red seguiría funcionando, pero el aprendizaje sería más lento, ya que estaría aplicando softmax dos veces.
Cargar los datos en la memoria
Al usar PyTorch, carga datos en la memoria en matrices de NumPy y, a continuación, convierte las matrices en objetos Tensor de PyTorch. En términos generales, un objeto Tensor puede considerarse como una matriz sofisticada que se puede administrar mediante un procesador de GPU.
Hay varias maneras de cargar datos en una matriz de NumPy. Entre mis compañeros, la técnica más común es usar el paquete de Python Pandas (originalmente denominado "datos del panel" y ahora "análisis de datos de Python"). Sin embargo, Pandas incluye un poco de curva de aprendizaje, por lo que, por motivos de simplicidad, el programa de demostración usa la función loadtxt de NumPy. Los datos de aprendizaje se cargan del modo siguiente:
train_file = ".\\Data\\iris_train.txt"
train_x = np.loadtxt(train_file, usecols=range(0,4),
delimiter=",", skiprows=0, dtype=np.float32)
train_y = np.loadtxt(train_file, usecols=[4],
delimiter=",", skiprows=0, dtype=np.float32)
PyTorch espera que los valores de predicción se encuentren en una matriz de estilo matriz de matrices y que los valores de clase que se predecirán se encuentren en una matriz. Una vez se ejecutan estas instrucciones, la matriz train_x tendrá 120 filas y cuatro columnas, y train_y será una matriz con 120 valores. La mayoría de las bibliotecas de redes neuronales, incluido PyTorch, usan datos float32 como tipo de datos predeterminado, ya que los problemas de rendimiento que comportan no compensan la precisión que se obtiene al usar las variables de 64 bits.
Entrenamiento de la red neuronal
La demostración crea la red neuronal y, a continuación, prepara el aprendizaje con estas instrucciones:
net = Net()
net = net.train() # set training mode
lrn_rate = 0.01; b_size = 12
max_i = 600; n_items = len(train_x)
loss_func = T.nn.CrossEntropyLoss() # applies softmax()
optimizer = T.optim.SGD(net.parameters(), lr=lrn_rate)
batcher = Batch(num_items=n_items, bat_size=b_size)
Establecer la red en modo de aprendizaje no es necesario para la demostración, ya que el aprendizaje no usa la normalización dropout o batch, que tienen diferentes flujos de ejecución para el aprendizaje y la evaluación. La velocidad de aprendizaje (0,01), el tamaño del lote (12) y las iteraciones de aprendizaje máximo (600) son hiperparámetros. La demostración usa iteraciones en lugar de épocas, ya que una época normalmente hace referencia al procesamiento de todos los elementos de aprendizaje de uno en uno. En este caso, una iteración significa que solo se procesan 12 de los elementos de aprendizaje.
La función CrossEntropyLoss se usa para medir el error para los problemas de clasificación de varias clases, en los que hay tres o más clases para predecir. Un error común es probarlo y usarlo para la clasificación binaria. La demostración usa el descenso de gradiente estocástico, que es la forma más rudimentaria de optimizar el aprendizaje. Para los problemas realistas, PyTorch admite algoritmos sofisticados que incluyen una estimación de momento adaptativa (Adam), un gradiente adaptativo (Adagrad) y una propagación de la media al cuadrado resistente (RMSprop).
La clase Batch definida por el programa implementa el mecanismo de procesamiento por lotes más simple posible. En cada llamada a su función next_batch, se devuelven 12 índices seleccionados de manera aleatoria de los 120 índices de datos de aprendizaje posibles. Este enfoque no garantiza que todos los elementos de aprendizaje se usarán el mismo número de veces. En un escenario que no sea de demostración, probablemente querría implementar un generador de lotes más sofisticado que seleccionara aleatoriamente los índices diferentes hasta haberlos seleccionado todos una vez y, a continuación, se restableciera automáticamente.
El aprendizaje se realiza exactamente 600 veces. Cada 600 / 10 = 60 iteraciones, la demostración muestra información del progreso:
for i in range(0, max_i):
if i > 0 and i % (max_i/10) == 0:
print("iteration = %4d" % i, end="")
print(" loss = %7.4f" % loss_obj.item(), end="")
acc = accuracy(net, train_x, train_y)
print(" accuracy = %0.2f%%" % acc)
El valor medio de error o de pérdida de entropía cruzada del lote actual de 12 elementos de aprendizaje puede obtenerse a través de la función del elemento del objeto. En general, la pérdida de entropía cruzada es difícil de interpretar durante el aprendizaje, pero debe supervisarla para asegurarse de que se reduce gradualmente, lo que indica que el aprendizaje funciona.
De forma un poco excepcional, en el momento en que escribo este artículo, PyTorch no tiene ninguna función incorporada que le ofrezca precisión para la clasificación. La función de precisión definida por el programa calcula la precisión de clasificación del modelo mediante los valores actuales de ponderaciones y sesgos. La precisión es mucho más fácil de interpretar que la pérdida o el error, pero es una métrica más cruda.
Dentro del ciclo de aprendizaje, se selecciona un lote de elementos del conjunto de datos de 120 elementos y se convierte en objetos Tensor:
curr_bat = batcher.next_batch()
X = T.Tensor(train_x[curr_bat])
Y = T.LongTensor(train_y[curr_bat])
Recuerde que curr_bat es una matriz de 12 índices de los datos de aprendizaje, por lo que train_x[curr_bat] tiene 12 filas y cuatro columnas. Esta matriz se convierte en objetos Tensor de PyTorch al pasar dicha matriz a la función Tensor. Si tiene un problema de clasificación, debe convertir los valores de la etiqueta de clase codificada en objetos LongTensor en lugar de objetos Tensor.
El aprendizaje real se realiza a partir de estas cinco afirmaciones:
optimizer.zero_grad()
oupt = net(X)
loss_obj = loss_func(oupt, Y)
loss_obj.backward()
optimizer.step()
Básicamente, puede considerar estas afirmaciones como conjuros mágicos de PyTorch que realizan aprendizaje mediante la retropropagación. Primero, debe poner a cero los valores de gradiente de ponderación y sesgo de la iteración anterior. La llamada a la función de red pasa el lote actual de 12 objetos Tensor a la red y calcula los 12 valores de salida mediante la función forward. Las llamadas a retroceso y paso calculan los valores de gradiente y los utilizan para actualizar las ponderaciones y los sesgos.
Evaluar y usar el modelo
Una vez finalizado el aprendizaje, la demostración calcula la precisión del modelo en los datos de prueba:
net = net.eval() # set eval mode
acc = accuracy(net, test_x, test_y)
print("Accuracy on test data = %0.2f%%" % acc)
Como antes, no es necesario configurar el modelo en modo de evaluación en este ejemplo, pero tampoco va mal ser explícito. El programa de demostración no guarda el modelo entrenado, pero en un escenario que no sea de demostración es posible que quiera hacerlo. PyTorch, junto con la mayoría de las otras bibliotecas de redes neuronales (con la notable excepción de TensorFlow), admite el formato de intercambio abierto de redes neuronales (ONNX).
La demostración utiliza el modelo entrenado para predecir las especies de una nueva flor de Iris que no se había visto anteriormente:
unk = np.array([[6.1, 3.1, 5.1, 1.1]], dtype=np.float32)
unk = T.tensor(unk) # to Tensor
logits = net(unk) # values do not sum to 1.0
probs_t = T.softmax(logits, dim=1) # as Tensor
probs = probs_t.detach().numpy() # to numpy array
La llamada a la función de red devuelve tres valores que no necesariamente suman 1.0, por ejemplo, (3,2, 4.5, 0.3), por lo que la demostración aplica softmax para que fuerce los valores de salida a que sumen 1.0 y puedan interpretarse libremente como probabilidades. Los valores son objetos Tensor, por lo que se convierten en una matriz NumPy para que puedan mostrarse más fácilmente.
Resumen
En este artículo hemos visto por encima la biblioteca de PyTorch, pero con él debería obtener toda la información que necesita para comenzar a experimentar. Tal y como demuestra este artículo, PyTorch es bastante diferente y opera a un nivel más bajo que CNTK, TensorFlow y scikit-learn. Una pregunta común es: "¿Cuál es la mejor biblioteca de redes neuronales?" En un mundo perfecto, podría dedicar un tiempo a ese tema y descubrir las principales bibliotecas. Pero como estas bibliotecas son bastante complicadas, en realidad la mayoría de mis compañeros tienen una biblioteca principal. En mi opinión, desde un punto de vista técnico, las tres mejores bibliotecas son CNTK, Keras/TensorFlow y PyTorch. Sin embargo, todas son excelentes y elegir una en lugar de otra depende en gran medida de su estilo de programación y de cuál es la que más usan sus compañeros o empresa.
El Dr. James McCaffrey trabaja para Microsoft Research en Redmond, Washington. Ha colaborado en varios productos de Microsoft, incluido Internet Explorer y Bing. Puede ponerse en contacto con el Dr. McCaffrey en jamccaff@microsoft.com.
Gracias a los siguientes expertos técnicos de Microsoft por revisar este artículo: Brian Broll, Yihe Dong y Chris Lee