Programación orientada a objetos en PyTorch

En este post vamos a repasar algunos conceptos de programación orientada a objetos que son necesarios para comprender el funcionamiento de PyTorch. Recordemos que Python es un lenguaje orientado a objetos y que PyTorch hace uso de esta capacidad para hacer más fácil su uso.

La programación orientada a objetos es un paradigma de programación que permite estructurar los programas para que las propiedades y los comportamientos se agrupen en objetos individuales.

Por ejemplo, en PyTorch una de las clases más importantes de torch.nn es torch.nn.Module ya que nos permite extenderla y usar multitud de métodos y atributos interesantes.

A continuación presentamos de manera resumida algunos conceptos de programación orientada a objetos:

  • Clase: Es un modelo que define los elementos necesarios para crear un objeto que pertenezca a esta clase.
  • Objeto: Es una instancia de una clase con atributos concretos.
  • Atributos: Tanto las clases como los objetos pueden tener atributos, que son características de estos. Los atributos pueden ser del objeto, que son específicos de la instancia, o de la clase, que son los mismos para todas las instancias de una clase.
  • init(): Todas las clases tienen este método, que se ejecuta cuando la clase está siendo instanciada y se crea un objeto. Se utiliza para asignar valores a los atributos de un objeto.
  • Parámetro self: Es una referencia a la instancia actual de la clase. Usándolo podemos acceder a los atributos y métodos de la clase en Python.
  • Métodos del objeto: Los objetos también contienen métodos, que son funciones que especifican un comportamiento determinado.

A continuación mostramos como ejemplo una clase con dos atributos, el método init() y un método definido. Creamos una instancia u objeto de la clase y llamamos al método del objeto.

#Definimos la clase
class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  #Definimos el método myfunc dentro de la clase
  def myfunc(self):
    print("Hola mi nombre es " + self.name)

#Creamos una instancia de la clase con los atributos Martin y 32
p1 = Person("Martin", 32)

#Llammamos al método myfunc de la instancia creada
p1.myfunc()
Hola mi nombre es Martin

En el ejemplo anterior, hemos visto como una clase se puede llamar directamente para crear una instancia u objeto. En cambio, para que un objeto sea «llamable», la clase correspondiente tiene que tener definido el método call().

A continuación vamos a definir el método call() en la definición de la clase para que el objeto sea «llamable» directamente.

#Definimos la clase
class Person:
  def __init__(self, name, age):
    self.name = name
    self.age = age

  #Definimos el método __call__() dentro de la clase
  def __call__(self):
    return self.age  
  
  #Definimos el método myfunc dentro de la clase
  def myfunc(self):
    print("Hola mi nombre es " + self.name)

#Creamos una instancia de la clase con los atributos Martin y 32
p1 = Person("Martn", 32)

#Llammamos diretamente a la instancia creada
p1()

32

Otro concepto muy importante es programación orientada a objetos es el de la herencia, que permite que una clase use los atributos y métodos de otra. La clase hijo se deriva de la clase padre.

La clase hijo sobreescribe o extiende la funcionalidad (métodos y atributos) de la clase padre, es decir, hereda todos los métodos y atributos de la clase padre pero también puede modificarlos o definir los suyos propios.

En PyTorch, cuando definimos un modelo de deep learning, normalmente definimos una clase que extiende la clase torch.nn.Module, para aprovechar los atributos y métodos que está clase tiene definidos.

Para ello, es necesario:

  • En el constructor del modelo init() inicializamos la superclase con super.init(), de esta forma podemos usar los atributos de la clase padre torch.nn.Module.
  • En init() también definimos los componentes que queremos que tenga el modelo, como por ejemplo cada una de las capas.
  • Sobreescribimos el método forward que realiza el forward pass con las operaciones para calcular la/s salida/s.
  • El método call() llama al método forward por lo que el objeto creado cuando instanciamos la clase definida será directamente «llamable».

A continuación vamos a definir la clase Net, que extiende la clase nn.Module definiendo una red neuronal con una capa intermedia.

import torch
import torch.nn as nn

class Net(nn.Module):
    def __init__(self, input_size, hidden_size, num_classes):
        super(Net, self).__init__()                    
        self.fc1 = nn.Linear(input_size, hidden_size)  
        self.relu = nn.ReLU()                          
        self.fc2 = nn.Linear(hidden_size, num_classes) 
    
    def forward(self, x):                              
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

Como se puede ver, en el constructor init() inicializamos la superclase nn.Module y definimos la capa lineal, el rectificador y una última capa lineal. Sobreescribimos el método forward con el flujo de operaciones a realizar a partir de la entrada x.

Ahora creamos una instancia u objeto del modelo con los parámetros especificados en init() y llamamos directamente a la instancia creada «modelo1» pasándole el tensor de entrada x. In [5]:

#Creamos una instancia del modelo
modelo1=Net(150,200,10)
#Llamamos a la instancia creada para calcular la salida
x=torch.rand(150)
output=modelo1(x)
print(output)

#Vemos la estructura del modelo
print(modelo1)
tensor([ 0.2396,  0.2677, -0.0952,  0.1885, -0.0029, -0.0093,  0.2247,  0.1506,
        -0.1617,  0.0995], grad_fn=<AddBackward0>)
Net(
  (fc1): Linear(in_features=150, out_features=200, bias=True)
  (relu): ReLU()
  (fc2): Linear(in_features=200, out_features=10, bias=True)
)

Hemos visto los principales conceptos de programación orientada a objetos y como se utilizan en PyTorch para poder extender clases y facilitar así la creación de modelos de deep learning.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Orgullosamente ofrecido por WordPress | Tema: Baskerville 2 por Anders Noren.

Subir ↑

A %d blogueros les gusta esto: