Programadores Precisam Aprender SQL!

De uns tempos para cá, tenho vistos muitos códigos bizarros acontecendo no mundo dos ORMs, que eventualmente me deixaram pensando: será que ORMs estão fazendo-nos esquecer como se faz SQLs?

No mundo Ruby/Rails, virou quase uma regra não-escrita que escrever SQLs na mão é errado. Quanto mais pudermos aproveitar o ActiveRecord (e algumas mágicas que ele faz por nós), melhor. Isso acaba trazendo algumas coisas bem esquisitas, tal como achar que 90% dos códigos nunca vão precisar de “OR” (e maior, menor, diferente, etc), já que a API do ActiveRecord não suporta isso, ou algumas outras práticas meio estranhas. Do outro lado, temos por exemplo o framework “Play!”, de Scala, que faz o extremo oposto: não usa nenhum ORM, e todas as queries SQL passam a ser feitas na mão…

O ponto é que quando temos um ORM, parece que abusamos dele e esquecemos que nem tudo é um “SELECT * FROM <table> WHERE <attribute> = <value>”. Por exemplo, no código abaixo:

users = User.all
users.each do |user|
  puts &quot;User #{user.name} has #{user.addresses.count} addresses&quot;
end

Temos o famoso caso do “N+1”: 1 busca para achar N usuários, e a partir daí “N” buscas para achar a contagem de endereços. O problema é que muita gente acha que apenas um “User.include(:addresses)” resolve o problema, quando na verdade não resolve: o “include” vai trazer todos os endereços, mas a contagem (se o Rails optar por usar “count”) vai continuar sendo feita em banco, ou então (se o Rails optar por não usar “count”) será feita em Ruby, e teremos trazido registros a mais do banco de dados sem necessidade. A solução, nesse caso, é usar um comando SQL mesmo:

users = User.all
num_addresses = Address.join(:user).group('user.id').count
users.each do |user|
  puts &quot;User #{user.name} has #{num_addresses[user.id]} addresses&quot;
end

Ok, mas SQL é difícil, chato, e é mais fácil fazer as coisas em Ruby, certo? Bom, sim e não. É mais fácil fazer os comandos em Ruby (ou na linguagem que você escolher) puramente por “costume”. Estamos acostumados a fazer a sequencia: buscamos uma lista, tratamos a lista, exibimos a lista. SQL não trabalha com “listas”, mas com “conjuntos”. E é isso que vamos ver a seguir:
(more…)

Resourceful Web

Todos sabem que, com o tempo, os frameworks web evoluem. Porém, o que poucas pessoas percebem é que além das mudanças nas APIs e na estrutura dos programas feitos com o framework, há uma mudança também nas idéias dos desenvolvedores e até mesmo nas metáforas que o sistema usou para definir-se. E o Rails não é exceção.

Por exemplo, no Ruby on Rails versão 1.x, a idéia do framework era a construção de aplicações web. Para tal, a idéia era que a aplicação fosse simples e divertida de desenvolver. Além disso, havia a idéia de web-services, XML-RPC e SOAP que nunca pegaram direito no mundo Rails (mas que estavam presentes na versão 1.x). Depois, na versão 2.x, surgiu o conceito de RESTful (em contraponto aos web-services do Rails 1) e, junto com ele, o conceito de “resource” ou “recurso”. Já no Rails 3, surgiu a idéia de separar o Javascript do HTML usando o conceito de Unobtrusive Javascript (Javascript não-intrusivo), e junto com essa idéia, veio a substituição do prototype pelo jQuery (que torna certas operações envolvendo AJAX mais fáceis). Junto também com a substituição por jQuery, o scaffold passou a fazer os controllers responderem por HTML e JSON, ao invés de HTML e XML como no rails 2.x.

E é essa a mudança mais importante.

Vamos começar pensando: qual seria o motivo de renderizar um JSON? A resposta é simples: JSON é mais fácil de ser entendido pelo browser, por Javascript, e por aplicativos de terceiros tais como em iOS ou Android. Antes, responder por XML não tinha aplicação real nenhuma nos próprios aplicativos Rails, e ficavam apenas como forma de comunicação com sistemas de terceiros (o velho “big design up front“) que nem sempre ocorriam. E hoje, renderizar JSON está muito pouco utilizado mesmo no mundo Rails, e há um motivo para isso:

Não sabemos o que é um “resource”.
(more…)

Redes Neurais – Parte 3

Ok, vamos finalmente para a terceira parte sobre Redes Neurais (e também, aonde será apresentado o código completo de uma rede neural em Ruby). Este post será sobre treinamento de redes neurais, especificamente sobre o treinamento dos pesos que saem dos neurônios de entrada e vão para os neurônios ocultos da rede. Antes de mais nada, vamos relembrar nosso desenho da rede neural:

Neural

Já vimos no post anterior que para achar o valor que MAXIMIZA a função de custo, usamos o métoodo chamado de “gradiente”. O método “gradiente” usa derivadas parciais, e como vamos achar o valor de um peso que sai do neurônio de entrada para o neurônio da camada oculta, precisamos calcular a derivada parcial da função de custo em relação a um destes pesos. Vamos usar o “peso_a1_b2” para este exemplo.

Antes de mais nada, vamos relembrar todas as contas que fazemos para nossa rede neural. Para tal, eu vou usar a notação “peso_ax_by” para indicar o peso que sai do neurônio “ax” e vai para o neurônio “by”. Note que NÃO EXISTE “peso_a1_b1”, porque o neurônio “b1” é o “bias”, logo o valor dele é sempre “1” (e não faria sentido calcular um valor se ele vai descartá-lo e usar “1”, no fim das contas). Sabemos que o valor de um neurônio oculto é a soma de todos os valores dos neurônios de entrada (multiplicados por seus devidos pesos) e aplicadas uma “função de ativação” (que no nosso caso, é a “Tangente Hiperbólica”). Eu vou chamar de “b_sem_ativacao_x” o valor desta soma dos neurônios de entrada, ANTES de se aplicar a função de ativação. Logo, nossas contas são:

b\_antes\_ativacao\_2 = a1 * peso\_a1\_b2 + a2 * peso\_a2\_b2 + a3 * peso\_a3\_b2 \\  b\_antes\_ativacao\_3 = a1 * peso\_a1\_b3 + a2 * peso\_a2\_b3 + a3 * peso\_a3\_b3 \\  b\_antes\_ativacao\_4 = a1 * peso\_a1\_b4 + a2 * peso\_a2\_b4 + a3 * peso\_a3\_b4 \\  \\  b2 = tanh(b\_antes\_ativacao\_2) \\  b3 = tanh(b\_antes\_ativacao\_3) \\  b4 = tanh(b\_antes\_ativacao\_4) \\  \\  c1 = b1 * peso\_b1\_c1 + b2 * peso\_b2\_c1 + b3 * peso\_b3\_c1 + b4 * peso\_b4\_c1 \\  c2 = b1 * peso\_b1\_c2 + b2 * peso\_b2\_c2 + b3 * peso\_b3\_c2 + b4 * peso\_b4\_c2 \\  \\  custo = \frac{1}{2 * N} * \sum\limits_{n=1}^N \sum\limits_{i=1}^2 (ci(do\ exemplo\ n) - yi(do\ exemplo\ n)) ^ 2
(more…)

Redes Neurais – Parte 2

No post anterior, vimos como montar a estrutura de uma rede neural. Neste post, veremos como fazer o treinamento dos pesos, para que a rede generalize nossos exemplos de teste e seja capaz de classificar exemplos que ainda não foram vistos. Num primeiro momento, vamos relembrar o desenho de uma rede neural:

Neural

Para facilitar, deixei um nome para cada neurônio (nota: provavelmente vocês não vão encontrar essa forma de nomear os neurônios em lugar algum-eu coloquei essa nomenclatura mais para facilitar o post do que para ser uma abordagem matemática mesmo). Os neurônios “a1” e “b1” são “bias”, conforme vimos no post anterior, e os neurônios “c1” e “c2” são os neurônios de saída. Note que este desenho de rede neural não representa nossa rede neural, pois nossa rede neural precisaria de 5 neurônios de entrada e 3 de saída. Bom, conforme vimos no post anterior, num primeiro momento os pesos sinápticos (as linhas ligando os neurônios, representadas pelas matrizes “input_weights” e “hidden_weights” no post anterior) são aleatórios, o que significa que a rede possuirá comportamento aleatório. A partir deste ponto, temos que alterar os pesos para tentar chegar num resultado melhor da rede. Para tal, precisamos de uma função que nos mostre quão bom é a solução atual: uma “função de custo”.
(more…)

Redes Neurais For Dummies

Ultimamente, muito tem-se falado sobre “machine learning” e redes neurais, então resolvi tentar trazer à luz alguns conceitos que eu tenho aprendido e que tem pouca (ou nenhuma) informação fácil na internet. A primeira coisa a se pensar é que todo o conceito de Redes Neurais, SVM, e outras técnicas de Machine Learning são áreas da matemática, portanto tudo o que for processado numa Rede Neural tem que, de alguma forma, ser convertido para números (o que não é exatamente um problema na maioria dos casos).

As redes neurais podem ser usadas para prever determinados valores, mas são principalmente usadas no processo de classificação de algo (por exemplo, eu tenho um conjunto de sintomas e quero classificar esse conjunto em uma doença conhecida) ou clusterização/agrupamento de valores (da mesma forma, eu tenho um conjunto de características de um país e quero separá-lo em conjuntos). Existem vários modelos de redes neurais, e neste primeiro post vou falar da rede perceptron. Este post está dividido em duas partes, a primeira (este post) será a montagem de uma rede neural, e a segunda, será sobre o treinamento da rede.

Neural
(more…)

Usando a Tipagem de Scala para Validar Parâmetros

Bom, primeiramente, muita coisa aconteceu por isso a falta de postagens, mas espero que daqui pra frente seja possível postar mais coisas interessantes.

Esses dias, estou tentando encapsular um código Java em um código Scala, basicamente, um código de matrizes, multiplicação de matrizes, etc, e será este o exemplo que usarei neste post. Para os que não lembram de matrizes, as operações sobre matrizes devem seguir uma determinada regra, por exemplo, adição de matrizes só podem ser efetuadas quando as duas matrizes possuem mesmo número de elementos:

class Matrix(protected val list: List[List[Double]] {
  def +(other: Matrix) = new Matrix(list zip other.list map { case(me, other) =&gt;
    me zip other map { case(e1, e2) =&gt; e1 + e2 }
  })
}

Para os que não conhecem tão bem Scala, o código a seguir soma uma matriz com a outra chamando o método zip, que basicamente, de posse de dois objetos que possam ser iterados (tipo um List), combinam seus elementos:

List(1, 2, 3) zip List(4, 5, 6)
=&gt; List( (1, 4), (2, 5), (3, 6) )
List(List(1, 2)) zip List(List(3, 4))
=&gt; List( (List(1, 2), List(3, 4)) )

O “case”, no map (e no foreach, e em qualquer closure) separa os dois elementos. Seria possível separar também com map { e => e._1, e._2 } mas fica um pouco mais feio o código.

Legal, o código acima funciona mas… ele permite somar matrizes de dimensões diferentes. Claramente, isso não é desejado. Podemos fazer o método nos retornar um erro quando tentarmos somar matrizes de dimensões diferentes:

  def +(other: Matrix) = {
    require(list.size == other.list.size, &quot;Number of rows must be the same&quot;)
    require(list(0).size == other.list(0).size, &quot;Number of cols must be the same&quot;)

    new Matrix(list zip other.list map { case(me, other) =&gt;
      me zip other map { case(e1, e2) =&gt; e1 + e2 }
    })
  }

Ou podemos usar a tipagem para isto.
(more…)

Scala, Traversable, e Implicits

Meu primeiro post bem técnico sobre Scala, vamos ver no que dá (rs).

Bom, primeiro, um pouco de “background”: comecei o fantástico curso de Machine Learning no site coursera.org, e todas as lições que estão no site são em Octave/Matlab. Não conhecia Octave, muito menos Matlab, e quando programei nestas linguagens descobri algumas coisas meio estranhas (bom, eu pelo menos considero estranho que, ao esquecer de colocar um “;” no final de um comando, ele imprima o resultado na tela), além, claro, de não ser possível programar pra Android, por exemplo.

Como estou estudando Scala, e como já consegui fazer Scala rodar no Android de um jeito menos “doloroso” (mais sobre isso em outro post), resolvi fazer os códigos em Scala. Há bibliotecas boas de multiplicação de matrizes em Scala, porém comparadas com as versões Java, elas são BEM mais lentas. Foi aí que pensei: por que não encapsular uma dessas bibliotecas Java em Scala?

Tudo correu bem, até o momento que resolvi que queria que cada matriz funcionasse como um Traversable. Para quem é de Ruby, o Traversable é equivalente ao Enumerable, com algumas coisas a menos e outras a mais. Só para comparar, vamos ver o código dos dois (para simplificar, vou omitir alguns códigos, mas a API é a seguinte: Matrix#rows e Matrix#cols para saber o número de linhas e colunas, Matrix#* multiplica matrizes ou uma matriz com um número. Também, a matriz possui um atributo, “list”, que contém um array de arrays com os elementos internos da matriz).

class Matrix(list: List[List[Double]]) extends Traversable[Double] {
  def cols = 3 //Só pro nossos códigos de exemplo compilarem...
  def foreach[B](function: Double =&gt; B) = list.flatten.foreach { e =&gt; function(e) }
}
class Matrix
  include Enumerable
  def each(&amp;b)
    list.flatten.each &amp;b
  end
end

Repare que o código é semelhante nas duas linguagens, a diferença básica é que em Ruby não precisamos definir tipos, em Scala precisamos (não que nesse caso faça alguma diferença). Só que temos um caso engraçado tanto em Ruby como em Scala: se queremos um método que, digamos, eleve todos os elementos ao quadrado, elemento por elemento, ao usar “map” para fazer esse processo, ele vai nos retornar, em Ruby, um Array, e em Scala, um Traversable[Double]. E pior, os elementos vão ficar “achatados”. Em ambos, é possível resolver isso fazendo o “each” (ou o “foreach”) retornar uma lista de elementos que está em cada linha, mas ainda assim temos o problema que nosso retorno será semelhante a um “array de arrays”, não uma matriz. O que fazer?

Bom, em Ruby, a gente se ferrou, literalmente. Não temos uma maneira de fazer isso que não envolva sobrescrever o map, e todos os métodos que constrõem uma lista a partir de outra. Em Scala, temos “implicits”, e um conceito “canBuildFrom”.
(more…)

Extraindo o Máximo do Android

Bom, estes dias comprei um Android, um Samsung Galaxy S2, e como todo bom usuário de Linux, já fiz algumas modificações no sistema. A coisa que achei mais diferente é a dificuldade de achar informações sobre como fazer as alterações, tal como “root” ou instalações de ROMs customizadas. Então, resolvi postar aqui como fazer estas alterações.

Em primeiro lugar, vale mencionar algumas coisas sobre o Android. Como todo Linux, ele possui um “kernel” separado do sistema. Além disso, o Android é dividido em um sistema base que fica montado em “/system”, e uma área para os dados dos aplicativos (possível de ser escrita pelo usuário) montado em “/sdcard”. No meu caso, ainda, ele possui um cartão SD externo, que fica montado em “/sdcard/external_sd”. Além disso há uma sopa de letras tipo “FactoryFS”, “Modem”, “Secondary Kernel” e outras coisas que eu entendo só por cima.

Para adquirir acesso “root”, há várias formas diferentes. Uma delas consiste em instalar um kernel diferente, mas aí você ganha um triângulo amarelo no seu celular quando você vai iniciá-lo, então todo mundo fica sabendo que você fez uma modificação. A outra, consiste em instalar um sistema de arquivos diferente. Basicamente o processo é fazer um “flash” no celular, com um kernel modificado (no primeiro caso) ou com um sistema modificado (no segundo). Para o Linux, uso o software “heimdall” (http://www.glassechidna.com.au/products/heimdall/). A versão 1.3.2 me deu problemas, então instalei a 1.3.1 e passei ao processo de flash. Eu recomendo o segundo método, pois o triângulo amarelo não fica presente, e basicamente consiste em baixar esta imagem: http://brasildroid.com.br/galaxy-s-ii-i9100-geral/6187-tutorial-root-ics-firmware-claro-tim-vivo-and-unbranded-oi.html. Depois, basta descompactá-la (usando zip ou rar), e você vai ter um arquivo .tar.md5 ou um arquivo .tar. Para descompactar esse arquivo, basta usar “tar -xf arquivo”, e finalmente a imagem está pronta para o processo de flash.

O processo de flash é bem simples, mas antes de fazê-lo, lembre-se de algumas coisas: primeiro, o suporte técnico da Samsung VAI encher o saco se descobrir que você fez uma modificação dessas no celular, e você pode perder a garantia. Segundo, faça o processo, de preferencia, de um notebook, e SEMPRE com o celular com bateria cheia ou quase cheia-não queremos que ausência de energia (tanto do PC como do celular) estraguem o processo todo, certo?

Então, para fazer o flash, basta deixar o celular num modo específico (modo de download) desligando-o e segurando “power+home+abaixar volume”. Ele pedirá uma confirmação, basta confirmar com o “aumentar volume”, e usar o heimdall. Eu rodei-o com o comando:

sudo heimdall flash --primary-boot boot.bin --cache cache.rfs --dbdata dbdata.rfs --factoryfs factoryfs.rfs  --modem modem.bin --param param.lfs --secondary-boot Sbl.bin --kernel zImage

Caso algum problema aconteça, não se desespere-basta tirar a bateria do celular e colocá-la novamente, e de novo deixa o celular em modo de “download” com a sequencia acima.

Enfim, com esse passo, seu celular terá acesso “root” e coisas interessantes podem ser instaladas (rastreadores que ligam automaticamente o GPS, por exemplo, ou o “Scala Installer” que pré-instala Scala no seu android e permite programar em Scala ao invés de Java, sem o processo de build demorado do proguard… mas mais sobre isso num outro post). Mas, se você quer algo mais hardcore, talvez seria interessante testar o CyanogenMod
(more…)

Android x iOS

Bom, comprei um android, depois da quebra do meu iPhone. Com três semanas de uso, acho que é interessante mencionar uma comparação dos dois, tentando ser o mais imparcial o possível.

Adiantando, eu estou gostando mais do android-mesmo reconhecendo que há pontos muito superiores no iPhone. Como forma de comparação, vou usar equipamentos com preços semelhantes (no caso, o aparelho android que tenho é um Samsung Galaxy S2). Termos como “o iPhone usa melhor o hardware porque um iPhone de 800mhz é comparável a um Android 1.2ghz” não fazem sentido aqui-de que adianta o processador ser mais fraco se, no fim, o preço do aparelho é o mesmo?

Enfim, começando pelo ponto mais positivo do Android-nada de iTunes. Sorry, folks, mas sinceramente o iTunes me lembra o Adobe Acrobat PDF Reader-um software que deveria fazer algo relativamente simples, e é pesado, lento, precisa de diversas atualizações (uma mais pesada que a outra) e necessita de uma super máquina pra rodar. Além disso, a idéia de “sincronizar músicas” do iTunes é uma porcaria-afinal, se eu tenho dois computadores, eu só posso sincronizar de um, caso contrário tenho que deletar TODA a minha playlist e começar de novo… não sei se no iTunes novo isto está corrigido (porque, como usuário de Linux, eu não usava o iTunes quase nunca).
(more…)