Las actualizaciones las carga el diablo

Este domingo por enésima vez a Lucía le salió la notificación de actualización de la MIUI 8. Cada semana lo mismo. Tiene mi viejo Xiaomi Redmi Note 4G, que compré en Febrero de 2015. A este teléfono le puse MIUI 8, la oficial. Esta ROM tiene activadas la actualización via OTA, y cada vez que se actualiza, pierde el rooteo, el recovery, etc.

En su momento ya le dije que no lo actualizase, que ocultase la notificación y en paz. El caso es que te deja bloquear las notificaciones de todas las aplicaciones, menos de las suyas ¡qué listos los de Xiaomi!. Al final, supongo que cansada de ver el mensajito de marras salir cada vez, lo actualizó.

Aquella vez fue bien, pero esta vez parece que los de Xiaomi han descuidado algo y la actualización provocó que salga un mensaje de “la aplicación android.com.p* se ha cerrado” que se repite insistentemente.

Repetí el upgrade, y nada. Lo restauré de fábrica, y nada. Le quité la SIM, la SD y nada. Le puse el TWRP Recovery, bajé una MIUI8 personalizada y lo mismo. Borré cachés y demás y nada.

Bajé la MIUI 7, ¡y me hacía lo mismo otra vez!. A las 12 de la noche de un domingo, esto como que te desespera un poco. Al final le dije a Lucía, ¿Tienes algo aquí que quieras guardar? ¿no? pues hale: formateo completo, incluido /system. Todo. Se libró la SD porque estaba fuera del teléfono. Reinstalé la MIUI7, reinicie y….

device-2012-09-30-203914

Y se pasó 40 minutos arrancando el móvil y seguía pantalla en negro con el logo de la MIUI. Volví a reiniciar, lo mismo otra vez.

Total que al entrar al TWRP para reinstalar de nuevo me avisó de que /system estaba montada en sólo lectura (o algo así). ¿Cambiar? ¡Claro! y ya de paso reinstalo por cuarta vez.

Al final me arrancó. Joder lo que sudé. La una de la noche casi y ya nos habíamos hecho a la idea de que Lucía estaría sin teléfono hasta el lunes por la tarde como muy pronto. Eso, si es que lo arreglaba. Pues se arregló, y fue ehm… lunes.

La ROM que tiene es una custom MIUI7 hecha por el foro de miui.es, que no tiene OTA y viene preparada con Google Play. Dado que Xiaomi ya ha decretado el EOL en este teléfono, creo que la mejor ROM posible es ésta, ya que la MIUI8 sobre KitKat da problemas con OsmAnd, y a Xiaomi parece preocuparle poco.

Os dejo el enlace a la ROM por si le interesa a alguien: [ROM] [MIUI7][GLOBAL_MIUIES_MOD][DESARROLLO 6.5.12/ESTABLES] Redmi Note 4G – 06/MAY/16

La conclusión es que las actualizaciones las carga el diablo. Ellos la envían y los que la sufren somos nosotros. Dependemos de los teléfonos mucho más de lo que queremos admitir y posiblemente podamos estar sin ordenador unos días, pero el smartphone se ha vuelto uno de los dispositivos más críticos en nuestra vida. Más crítico que quedarse sin gas en la cocina con la ternera en la sartén.

Así que desde algún tiempo considero el smartphone como “área en producción” y pienso en ellos del mismo modo que en los servidores: si algo funciona no lo toques. Más vale anticuado que quedarte sin móvil.

PD: Parece que OsmAnd tampoco funciona con la MIUI7. Es una pena. Con el teléfono rooteado se puede “parchear” borrándole la librería *.so que suele dejar en /data. Pero el rendimiento cae en picado, y el cálculo de ruta para más de 20km tiende a fallar.

Entropy Classifier Network (Part I)

The last week I did my first neural network on my own, using Theano. It is something simple compared with the real neural networks out there, but at least it serves to a purpose for me, for which I didn’t find out other ways to do it. I’m pretty sure there are other solutions for this, but I didn’t find any.

My network is an input entropy classifier. Its job is to find easily predictable data from training inputs (low entropy), and discard them from lowest entropy to highest. So we can sort columns by “data quality”.

The main problem behind this idea is, I have several training sets for MLP and others which are 1400 columns wide or more. Is not a big set, but when you want to do some tests, speed matters a lot and smaller inputs are way faster. I know some of my column inputs are correlated between them and I don’t need them. The problem is, I don’t know which columns should I select.

So I devised a method using a neural network that tries to predict every input column using every other input column available. Knowing which input columns get predicted first, I know these held more “discardable” information.

I started with a Logistic Regression from DeepLearning at lisa (Theano). If I was going to predict the column 1 of 1000, then I have a Neural Network of 999 inputs, and one output. The ouput should match the input I want to predict. Which, of course, should be avoided from the input so the network can’t learn to produce the output from the same input which is fairly easy and doesn’t give me any information about predictability.

For this, I had to change the cost function. In a logistic regression, the cost function is oriented as a classifier with multiple outputs. In my case I need to aproximate an analog output. For that I used a simple squared loss function:

cost = avg( (input - output) ^ 2 )

The problem now is that I need to run the network again for every column just to know which one to discard. And after those 1000 runs I will only know which column is the best candidate. This process should work, but I am not patient enough to wait for it.

I will wrote more about this in a few days…

 

Automatic data normalization

For neural networks is best to use normalized data. Specially when the data has to be predicted by the network, you need to make sure the values can be output by the network. Some of them work best between  ({-0.50} ... 0.50)

The problem is that sometimes we don’t know how to normalize it. With the exception of convolutional networks, which have a notion of input proximity, the others usually can be normalized on a per-column basis.

The most basic normalization is to calculate min(I_n) and min(I_n) and use them to normalize the output.

Get the data width as: width = (max - min)

Get he median point as: median = width / 2 + min

So the new Input would be: I'_{ny} = (I_{ny} - median) / width

With this formula all data in the input would be between   ({-0.50} ... 0.50), having the center point at zero.

There is of course a drawback when doing this, a small amout of information is being lost. As we do this in a per-column (per-pixel) basis, without retaining any structure or inferring some of this normalization to the related columns, we’re losing a small part of the interrelationship of the input columns.

If every column of the input comes from the same source, with the same methodology, probably is best to normalize the input as a whole and not per-column. For example, in images. In those cases even may be easy to guess the normalization we need to apply without using even formulas.

Maybe the input data can be divided into several blocks and we could normalize each block independently. The more you know about your data, the better. There is no general algorithm that can magically normalize every possible input better than what an human can do with the data source knowledge.

But sometimes we don’t know anything about the data, or maybe is costly to investigate column per column which should be the correct range. So in those cases, and maybe specially when we’rein a hurry to do some basic tests, it’s better to simply do a per-column normalization and stop worrying.

I was devising a method that automatically normalizes my data based on the histogram of it. It is an improved version of the above, because a min-max normalization can be understood as an histogram normalization of one bucket. The improvement here is, we don’t only want to pan & zoom into the data, we also want to detect which parts contain more data to enlarge them and detect which large parts barely contain data to shrink them.

In other words what we want to do is histogram equalization: https://en.wikipedia.org/wiki/Histogram_equalization

The basic approach is to create an histogram of N buckets (typically 255 for images), and from that data create a linear interpolation function which transforms the original value into a normalized one taking the histogram in account.

Sounds good, but doing this we’re losing information. Histogram itself helds information (which may be valuable or not) and this technique removes it, as the output has a flat histogram.

To understand this, see what happens to a image if you apply this technique. This is the well known photo of Lena and its equalized version:
lena_colorlena_color_equalized

As you may notice, after equalization a lot of information is more clearly visible. Colors are nearer to the original, skin tones are better, etc. But something is lost. The mood. In a part this did what we wanted to do: make information more visible. And this probably will work better than the original in almost any cases.

But I don’t want to remove the “mood” from the data. All I want is make it less noticeable. Shrinking it while retaining part of the original shape data.

Currently I’m doing a 20 bucket histogram, and I’m adding a 10% of value to every bucket to avoid equalizing too much (This limits data shrink to 10x). After that I do a cubic interpolation instead of a linear one so the function is smoother. To the output, I repeat the histogram and look for buckets with more than 20% of the data, If there is any, I repeat this procedure up to 3 times.

The code looks like this:

def check_input(i):
    rows, cols = i.shape
    numbins = 10
    for c in range(cols):
        new_ic = i[:,c]
        for n in range(8):
            arr_range = [np.min(new_ic), np.max(new_ic)]
            if arr_range[1]-arr_range[0] < 0.01: break
            arr_range[0] -= 0.01
            arr_range[1] += 0.01
            hist,bin_edges = np.histogram(new_ic, bins=numbins, density=True, range=(arr_range))
            hist2 = hist*np.diff(bin_edges)
            curmax = np.max(hist2)
            if curmax < 1.5 / numbins + 0.05 and n > 0: break
        
            cumhist = np.cumsum(hist2)
            y = (np.array([0]+list(cumhist))-0.7)+np.linspace(-0.05,0.05,num=numbins+1,endpoint=True)
            
            f2 = interp1d(bin_edges, y , kind='cubic')
            new_ic = f2(new_ic)
        if c % 32 == 0 or n > 2:
            print("%d/%d" % (c+1,cols), hist.shape[0], n, ">>", " ".join(["%.0f" % f for f in list((hist2*1000))]))
        i[:,c] = new_ic 
    return i

Still I’m not convinced, but works well for the moment. I decided to leave it “as is” for now.

I don’t have a configuration save/restore procedure and this will be a big issue in the future, as I can’t apply the same normalization to new data.

Other interesting resource about this:
http://scikit-image.org/docs/dev/auto_examples/plot_equalize.html

Reviviendo el blog

Finales de 2016 y me da ahora por revivir el blog. Será que algo hay para contar, porque los ultimos intentos se quedaron olvidados al poco tiempo.

El caso es que me estoy dedicando a aprender sobre redes neuronales, y me apetece compartir lo que aprendo con más gente. Ya contaré más en otra entrada sobre esto.

He organizado un poco. Había un blog hecho con blogger del ¿2006? Tenía un par de entradas. Era tan viejo que blogger daba error al modificarle el tema. Al final decidí borrarlo y continuar en wordpress. Las dos entradas las he pasado a mano aquí, no se si es morriña pero no quería perderlas, aunque ahora me sonroje un poco al leerlas.

Muchas cosas han cambiado en estos años, aunque otras no tanto. Sigo trabajando en Gestiweb y con el mismo coche (aún funciona bien y supone poco gasto, a pesar de que hace más kilómetros). La asociación cultural sedice cerró ahora hace un año, y me quedé con las webs. Con un servidor pequeño lo mantengo todo con donaciones.

Y mucho más se me queda por comentar, pero para el cotilleo social ya está el facebook. Aquí toca escribir sobre cosas que investigo y aprendo.

Así que nada, nos leemos! A ver que tardo esta vez en dejarlo abandonado…