Mojo: uma nova linguagem de programação para Inteligência Artificial

Mojo: uma nova linguagem de programação para Inteligência Artificial

Novamente a mesma história. A informática vive uma espécie de frase de Sísifo, pois de vez em quando se observa a mesma história, uma espécie de eterno retorno: o surgimento de uma nova linguagem de programação, um novo framework, uma nova biblioteca, etc. e, na maioria dos casos, há poucas novidades.

Por outro lado, há muita coisa antiga: Uma espécie de disfarce para agradar aos ávidos por novas ferramentas: “Só estou interessado em me manter atualizado” é o mantra comum. Mas nem tudo é negativo. Neste tsunami de tecnologias que surgem, de vez em quando, uma rouba a cena, não tanto pelo que promete – todos se elogiam pelo marketing – mas por quem promete.

No início de 2023 apareceu Mojo, uma linguagem de programação para Inteligência Artificial (IA) criada pela empresa Modular, liderada por Chris Lattner, criador do Swift (Apple) e do LLVM (principal ferramenta para construção de compiladores).

Minha primeira impressão foi de dúvida, pois de vez em quando surge uma nova linguagem que afirma ser uma ótima alternativa às já consagradas para IA (ou seja: Python, R, C++ e até Julia). Embora desta vez tenha sido diferente, porque quando vemos o nome de Lattner - que é um grande engenheiro - podemos pelo menos ter certeza de uma coisa: por trás do Mojo está a qualidade.

Neste artigo revisaremos cinco recursos do Mojo que o tornam digno de atenção. Farei então algumas considerações pessoais sobre a linguagem e concluirei com algumas sugestões.

Características

Mojo 🔥 é apresentado como um superconjunto Python (ou seja, mantém as mesmas funcionalidades e incorpora novas), com desempenho semelhante ao C.

A seguir apresentarei suas características mais notáveis ​​que, segundo seus autores, sustentam esta afirmação.

Importante: No momento da redação deste artigo (maio de 2023), só é possível utilizar o Mojo através de lista de espera, portanto devemos aguardar um pouco para que esteja disponível para todos.

Mojo tem o slogan de «a new programming language for all AI developers» (nova linguagem de programação para todos os desenvolvedores de IA). Com isso, prevemos então que todas as suas novidades foquem em enfatizar questões como desempenho e paralelização, fundamentais para a criação de sistemas de IA.

1) Suporte completo para Python

O roadmap do Mojo é usar o CPython como base e torná-lo totalmente compatível com o código Python. Algo semelhante a quando apareceu o C++, onde novos recursos (classes) foram incorporados sem perder a compatibilidade com C.

Agora, o Mojo tem as seguintes diferenças do Python.

  • Adicionar tipos. Mojo possui estruturas estáticas, enquanto Python possui classes dinâmicas. Além disso, as estruturas no Mojo permitem que você ganhe desempenho. Dentro deste tipo é possível utilizar as palavras reservadas var e let, onde a primeira define uma variável mutável e a segunda uma imutável.
  • Paralelismo nativo. Ao contrário do Python, o Mojo foi projetado para facilitar o trabalho com paralelismo, semelhante a outras linguagens como Julia.

Vou mostrar as outras características abaixo.

2) Tipos progressivos

Este sistema de tipos dá ao programador a responsabilidade por quais expressões em seu programa adicionam ou não tipos, variando a garantia do sistema. Em outras palavras, os sistemas de tipos progressivos permitem que os programadores aproveitem as vantagens dos tipos dinâmicos, bem como o melhor dos sistemas estáticos sempre que necessário.

Vejamos um exemplo:

def ordenamiento(v: ArraySlice[Int]):
  for i in range(len(v)):
    for j in range(len(v) - i - 1):
      if v[j] > v[j + 1]:
        swap(v[j], v[j + 1])

Aqui é atribuído o tipo ArraySlice[Int] para o argumento v da função ordenamento. Em Python isso não é possível: o mais parecido é atribuir um hint (anotação), mas em nenhum caso isso permite que funcione como um sistema de digitação estático, como o Mojo fornece.

Somado a isso, levanta questões mais profundas na implementação do compilador, uma vez que esses tipos progressivos aumentam suas garantias (correção) nas partes do código onde o programador disse para fazê-lo usando algum tipo.

Isso pode ser visto em como e onde surgem os erros.

3) Abstração de custo zero

Isso significa que funcionalidades de alto nível, como metaprogramação, inicialização de estrutura, algoritmos paramétricos (próximo recurso) ou qualquer outra abstração sofisticada podem ser adicionadas sem serem penalizadas em tempo de compilação (daí o custo zero).

struct Par:
  var primero: Int
  var segundo: F32
  
  def __init__(self, primero: Int, segundo: F32):
    self.primero = primero
    self.segundo = segundo

Neste exemplo, a estrutura Par tem dois atributos primeiro e segundo, ambos digitados estaticamente, que são então inicializados no construtor. Por exemplo, Python não possui abstrações de custo zero, portanto a estrutura Par, como qualquer abstração, tenderia a aumentar o tempo de compilação.

4) Algoritmos paramétricos portáteis

Permitem que você aproveite a metaprogramação – que funciona em tempo de compilação – para escrever algoritmos independentes de hardware e, assim, reduzir o código, por meio de seu tipo SIMD (Single Instruction, Multiple Data), que é um conjunto de instruções que representa um vetor de baixo nível em hardware.

Isso evita a adaptação do código para operar com diferentes arquiteturas de CPU como SSE, AVX-512, NEO, SVE, entre outras compatíveis com SIMD.

def exp[dt: DType, elts: Int]
    (x: SIMD[dt, elts]) -> SIMD[dt, elts]:
  x = clamp(x, -88.3762626647, 88.37626266)
  k = floor(x * INV_LN2 + 0.5)
  r = k * NEG_LN2 + x
  return ldexp(_exp_taylor(r), k)

Na função exp, o tipo SIMD é adicionado como argumento de entrada e para seu retorno. Esse tipo de recurso é útil para quem deseja aplicar otimizações de baixo nível no hardware, aproveitando-o melhor e ganhando desempenho em seus sistemas de IA (algo que normalmente não é simples em Python).

5) Autotuning integrado ao idioma

Ao trabalhar em baixo nível, há momentos em que para acelerar um algoritmo é necessário encontrar o ajuste correto nas dimensões dos vetores que dependem de cada hardware. Então, em vez de pesquisar e depois avaliar cada valor possível, usei o autotune, que faz essas verificações internamente e retorna o valor ideal mais adequado ao hardware.

def exp_buffer[dt: DType](data: ArraySlice[dt]):

  # Busca el mejor tamaño del vector desde varias posibilidades
  alias vector_len = autotune(1, 4, 8, 16, 32)
  
  # Lo usa para crear la vectorización
  vectorize[exp[dt, vector_len]](data)

O exemplo acima fornece cinco alternativas para inicializar as dimensões de um vetor. Sem uma função que busque o melhor valor possível, seria necessário realizar testes em cada caso, tornando-se uma tarefa tediosa.

Breves considerações

O site Mojo mostra uma tabela comparando-o com Python 3.10.9, PyPy e Scalar C++ na implementação do algoritmo Mandelbrot, em termos de tempo de execução.

Fonte: https://www.modular.com/mojo

Obviamente, é surpreendente – como todas as comparações presentes no site de uma nova linguagem de programação. No entanto, devemos ter cautela com este tipo de gráficos, pois escondem a implementação de cada alternativa, algo crucial para fazer uma comparação justa.

Outra consideração interessante de Mojo é a respeito de uma decisão que está escrita em seu repositório:

Acreditamos que um grupo pequeno e unido de engenheiros com uma visão compartilhada pode avançar mais rápido do que um esforço comunitário, por isso continuaremos a incubá-lo no Modular até que esteja mais completo..

Uma das vantagens de iniciar um projeto em uma comunidade é que você pode receber feedback de qualquer lugar, mas também nem sempre é aconselhável quando você está começando, pois é propenso a tomar decisões erradas de design que não podem ser modificadas posteriormente.

Assim, acho uma boa decisão deixar o coração do Mojo nas mãos de engenheiros especializados em design de linguagens, pelo menos antes de abri-lo para todos. Nesse ponto, é normal que surja a pergunta: Será que algum dia eles deixarão o código aberto? Já veremos.

Conclusão

Mojo é talvez a primeira linguagem de programação que se propõe a —árdua— tarefa de ter total compatibilidade com Python e, então, adicionar novos recursos e funcionalidades que a tornem tão eficiente quanto C.

Além disso, como visto neste artigo, o Mojo foi projetado para pessoas que não apenas trabalham no nível superior de aplicativos de IA, mas também para aqueles que precisam de mais controle no nível inferior, onde a otimização do hardware é essencial. Assim, adiciona uma camada não presente no Python: recursos de linguagens de baixo nível como C.

E embora possa parecer muito surpreendente com Chris Lattner - que já provou seu valor criando Swift e LLVM - como endosso, o melhor que podemos fazer é esperar para ver se ele nos surpreende novamente.


Algumas sugestões para acompanhar o desenvolvimento da linguagem:

  • Considere seguir o X (Twitter) da empresa Modular e o projeto no GitHub.
  • Tente se adicionar à lista de espera neste link estar entre os primeiros a usá-lo.
  • Acompanhe o relato do autor principal por trás do Mojo: Chris Lattner.

Referências

Notas

Os códigos foram extraídos e adaptados da documentação oficial do Mojo.

💡
As opiniões e comentários expressos neste artigo são de propriedade exclusiva de seu autor e não representam necessariamente o ponto de vista da Revelo.

A Revelo Content Network acolhe todas as raças, etnias, nacionalidades, credos, gêneros, orientações, pontos de vista e ideologias, desde que promovam diversidade, equidade, inclusão e crescimento na carreira dos profissionais de tecnologia.