2016年4月20日水曜日

Windows10でネットブックで画面の解像度をあげる

僕B5サイズのノートPCが大好きで、家でブラウザを使うのにネットブックを使っています。

東芝のUX23という機種を使っているのですが、Windows7とかWindows10を入れると、画面の解像度が1024*600になってしまい、一部のソフトが画面からはみ出して、ボタンをクリックできず使えません。

WindowsXPのときは液晶サイズより高い解像度を設定できたのに、Windows7以降は液晶サイズより高い解像度の設定ができないようで、とても不便です。

昔は新しいPCを買ってお金で解決したのですが、おじさんのように給料が下がってしまった人は知恵で解決していきます。

なかなかネットに解決方法が載っていないので、どうやったら画面の解像度を上げられるかいろいろ実験して調べてみました。

どうやら、レジストリにスケーリングONの設定をして、インテルのGMA950のグラフィックスドライバを入れれば画面の解像度を上げられるようです。


まず、IntelのGMA950(G945)のグラフィックスドライバ。

https://downloadcenter.intel.com/ja/product/81509/Graphics-Drivers-for-Mobile-Intel-945GM-Express-Chipset-Family

これをいれます。僕の時はバージョン: 15.12.75.4.1930というものを入れました。
これをいれずにレジストリを変更すると解像度を上たとたんにブルーバックになってしまいます。
Windows8以降ではインストーのル途中で古いバージョンのドライバーを入れようとしていますと聞かれますが、強制的に古いバージョンを入れます。


次にレジストリの書き換え。
拡張子が.regのファイルを作り、以下のテキストをファイルに書き込みます。
------------------------------
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E968-E325-11CE-BFC1-08002BE10318}\0000]
"Display1_DownScalingSupported"=dword:00000001
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Class\{4D36E968-E325-11CE-BFC1-08002BE10318}\0001]
"Display1_DownScalingSupported"=dword:00000001
------------------------------

そして、ファイルをクリックするとレジストリの変更ができ、PCを再起動すると設定が有効になります。

これで1024*600までしか画面の解像度の設定ができなかったPCが1024*768と1152*864の設定ができるようになります。

液晶サイズはもともと1024*600なので1024*768などに設定すると画面が縮小されてしまいますが、いままで大きい画面でないと使えなかったソフトが使えるようになります。

他のネットブックでもたいていIntelのGMA950のグラフィックアクセラレータなので、同様な方法で解像度を上げることができます。
Windows7、Windows8、Windows10で試しましたが、どのバージョンのWindowsでもこの方法が使えます。


2016年4月7日木曜日

C言語でレーベンバーグ・マーカート法(Levenberg-Marquardt)をやってみた

最小二乗法を実験するブログ、最終回の本日は、レーベンバーグ・マーカート法です。
最小二乗法は線形関数を推定する場合は簡単なのですが、非線形の場合とっても難しくなるようです。

ソースコードでいうと、線形の場合、C言語のファイルが一つなのですが、非線形の場合、ファイルが2000個近くになります。

ビッグマックセットに例えると、普通のビッグマックセット650円なのにグランドビックマックセット130万円って感じでしょうか。


とりあえず、C言語でレーベンバーグ・マーカート法をやるには以下の二つのライブラリがいります。

levmar
http://users.ics.forth.gr/~lourakis/levmar/

LAPACK
http://www.netlib.org/lapack/


levmarは名前からもわかるようにレーベンバーグ・マーカート法のライブラリです。
しかもこのライブラリはLAPACKというフォートラン言語で書かれたベクトル演算ライブラリを使っています。さらにLAPACKはBLASというライブラリを使っています。

フォートラン?
フォートランっていう言葉20年ぶりくらいに久しぶりに聞いた。


このLAPACKというライブラリをC言語からどうやって使うかというと

1.コンパイルしてあるライブラリをどっかから持ってきて使う

2.フォートランコンパイラでコンパイルして、ラッパーをCコンパイラでコンパイルして使う

3.f2cでフォートラン部分のソースコードをC言語に変換して、BLASとlibf2cとも一緒にコンパイルして使う。

このどれかの方法でやらないといけません。
一番簡単な1の方法を使おうと思ったのですが、VisualStudio2008用のライブラリしかない・・・・。

仕方がないので3の方法でコンパイルをすることにします。

f2cをかけたC言語のソースコードはCLAPACKというようで、以下のところにあります。
http://www.netlib.org/clapack/

CLAPACKのソースコードを取ってきて、Visual-C2015で頑張ってコンパイルします。
ひたすら2000ファイル近いソースコードをコンパイルし、エラー部分を修正していきます。
なんというめんどくさい作業。

さらに、levmarをCLAPACKに対応するように修正。

それでも半日くらいかければコンパイルすることができます。

http://kivantium.hateblo.jp/entry/20140408/p1

これでやっと上記のソースコードをVisualStudioで動かすことができました。


VisualStudioでも動くようにした、フルC言語のLAPACKとlevmarはこちら。
https://drive.google.com/open?id=0B5M9qMMg3tfQRDVRaWpuVVh1OWc


コンパイルが面倒ですが、一度作ってしまえばWindows版のBLASとLAPACKだけでもしばらくいろいろ遊んで楽しめそう。


2016年4月6日水曜日

勾配降下法をやってみた。

最小二乗法が簡単だったので調子に乗って勾配降下法をC言語で実装してみました。
関数の最小値を求めるもっとも簡単なやつです。
これも実装だけならば簡単。いろいろ実験して遊ぶのには最適です。
関数の傾きを求めてちょっとづつ移動していくやつです。

遊んでわかったことは初期値が平らなところから始まるとこれでもかと思うくらいなかなか値が収束しません。ダメじゃん。傾きを計算するのに導関数もいるしね。

ということでいつか非線形関数の最小二乗法のLevenberg-Marquardt法で最小値を求める実験でもやろうと思っているのですが、Levenberg-Marquardt法、とってもめんどくさいし数学的によくわからないので片手間ではブログ書けないのです。どうしよう・・・・。



---------------------------------------------

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define WIDTH 80
#define HEIGHT 25

//
//myplot
//

static char dot[HEIGHT][WIDTH];
static double off_x = 0.0;
static double off_y = 0.0;
static double scale = 1.0;

static void myplot_init(void)
{
int i;
memset(dot, ' ', HEIGHT*WIDTH);
for (i = 0; i < WIDTH; i++)dot[0][i] = '-';
for (i = 0; i < HEIGHT; i++){
dot[i][0] = '|';
dot[i][WIDTH - 1] = 0;
}
}

static void myplot_plot(double x, double y, char c)
{
int ix, iy;
x = (x - off_x)*scale * 2;
y = (y - off_y)*scale;
ix = (int)x;
iy = (int)y;
if (ix<0 || ix>WIDTH - 2)return;
if (iy<0 || iy>HEIGHT - 1)return;
dot[iy][ix] = c;
}

static void myplot_print(void)
{
int i;
for (i = 0; i < HEIGHT - 1; i++)printf("%s\n", dot[HEIGHT - 2 - i]);
}

void myplot_set_scale(double off_x_, double off_y_, double scale_)
{
off_x = off_x_;
off_y = off_y_;
scale = scale_;
}


//
// main
//
double f(double x)
{
return 20-exp(-x*x/20)*15;
}

double df(double x)
{
return 0.1*x*exp(-x*x / 20) * 15;
}

int main()
{

int i;
double x = 5;
double n = 0.1;

myplot_init();
for (i = 0; i < 10; i++){
myplot_plot(i * 10, 0, '+');
myplot_plot(0, i * 10, '+');
}
myplot_set_scale(-20, 0, 1);
for (i = -100; i < 100; i++)myplot_plot(i, f(i), '*');
//for (i = -100; i < 100; i++)myplot_plot(i, 3*df(i)+10, '@');
myplot_plot(x, f(x), 'S');

for (i = 0; i < 1000; i++){
x = x - n*df(x);
//printf("%f\n", x);
myplot_plot(x, f(x), 'A');
}
myplot_plot(x, f(x), 'E');
myplot_print();


return 0;
}


---------------------------------------------

最小二乗法をやってみた

たまには数値計算でもしてみようかなぁと思い、最近はやりの最小二乗法を作ってみました。
グラフツールとかインストールしていないので、コンソールにグラフを書く簡単なライブラリも作ってみました。


おーなんかあってるっぽいね。

-----------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>

#define WIDTH 80
#define HEIGHT 25

//
//myplot
//

static char dot[HEIGHT][WIDTH];
static double off_x = 0.0;
static double off_y = 0.0;
static double scale = 1.0;

static void myplot_init(void)
{
int i;
memset(dot, ' ', HEIGHT*WIDTH);
for (i = 0; i < WIDTH; i++)dot[0][i] = '-';
for (i = 0; i < HEIGHT; i++){
dot[i][0] = '|';
dot[i][WIDTH - 1] = 0;
}
}

static void myplot_plot(double x, double y, char c)
{
int ix, iy;
x = (x - off_x)*scale * 2;
y = (y - off_y)*scale;
ix = (int)x;
iy = (int)y;
if (ix<0 || ix>WIDTH - 2)return;
if (iy<0 || iy>HEIGHT - 1)return;
dot[iy][ix] = c;
}

static void myplot_print(void)
{
int i;
for (i = 0; i < HEIGHT - 1; i++)printf("%s\n", dot[HEIGHT - 2 - i]);
}

void myplot_set_scale(double off_x_, double off_y_, double scale_)
{
off_x = off_x_;
off_y = off_y_;
scale = scale_;
}


//
// saisyou2zyou
//

int gauss(double **w, int n, int m, double eps)
{
double y1, y2;
int ind = 0, nm, m1, m2, i1, i2, i3;

nm = n + m;

for (i1 = 0; i1 < n && ind == 0; i1++) {

y1 = .0;
m1 = i1 + 1;
m2 = 0;

for (i2 = i1; i2 < n; i2++) {
y2 = fabs(w[i2][i1]);
if (y1 < y2) {
y1 = y2;
m2 = i2;
}
}

if (y1 < eps)
ind = 1;

else {

for (i2 = i1; i2 < nm; i2++) {
y1        = w[i1][i2];
w[i1][i2] = w[m2][i2];
w[m2][i2] = y1;
}

y1 = 1.0 / w[i1][i1];

for (i2 = m1; i2 < nm; i2++)
w[i1][i2] *= y1;

for (i2 = 0; i2 < n; i2++) {
if (i2 != i1) {
for (i3 = m1; i3 < nm; i3++)
w[i2][i3] -= w[i2][i1] * w[i1][i3];
}
}
}
}

return(ind);
}

double *least(int m, int n, double *x, double *y)
{
double **A, **w, *z, x1, x2;
int i1, i2, i3, sw;

m++;
z = (double*)malloc(sizeof(double)*m);
w = (double**)malloc(sizeof(double*)*m);
for (i1 = 0; i1 < m; i1++)
w[i1] = (double*)malloc(sizeof(double)*(m + 1));
A = (double**)malloc(sizeof(double*)*n);

for (i1 = 0; i1 < n; i1++) {
A[i1] = (double*)malloc(sizeof(double)*m);
A[i1][m - 2] = x[i1];
A[i1][m - 1] = 1.0;
x1 = A[i1][m - 2];
x2 = x1;
for (i2 = m - 3; i2 >= 0; i2--) {
x2 *= x1;
A[i1][i2] = x2;
}
}

for (i1 = 0; i1 < m; i1++) {
for (i2 = 0; i2 < m; i2++) {
w[i1][i2] = 0.0;
for (i3 = 0; i3 < n; i3++)
w[i1][i2] += A[i3][i1] * A[i3][i2];
}
}

for (i1 = 0; i1 < m; i1++) {
w[i1][m] = 0.0;
for (i2 = 0; i2 < n; i2++)
w[i1][m] += A[i2][i1] * y[i2];
}

sw = gauss(w, m, 1, 1.0e-10);

if (sw == 0) {
for (i1 = 0; i1 < m; i1++)
z[i1] = w[i1][m];
}
else
z = NULL;

for (i1 = 0; i1 < n; i1++)
free(A[i1]);
for (i1 = 0; i1 < m; i1++)
free(w[i1]);
free(A);
free(w);

return z;
}

//
// main
//
int main()
{
double x[] = { 10, 15, 20, 26, 32, 40 };
double y[] = { 28.2, 47, 44.4, 32.8, 20.8, 0.8 };

double *z;
double d;
int i, m, n;

m = 2;
n = 6;

myplot_init();
myplot_set_scale(0, 0, 0.5);
for (i = 0; i < 10; i++){
myplot_plot(i * 10, 0, '+');
myplot_plot(0, i * 10, '+');
}
for (i = 0; i < n; i++)myplot_plot(x[i], y[i], '*');

z = least(m, n, x, y);

if (z == NULL)return 0;

for (i = 0; i < 80; i++){
d = z[0] * i * i + z[1] * i + z[2];
myplot_plot(i, d, 'o');
}

myplot_print();

free(z);

return 0;
}

-----------------------------------------------


2016年4月5日火曜日

自動微分をする

よく、コンピュータの理論を勉強する前に基礎である線形代数を勉強してほうが良いといわれています。

この線形代数なのですが、おじさんの時代は主にベクトルとか逆行列とかをやっていました。まぁゲームとかを作る際に座標の計算とかをしないといけないからなのですが。

しかしこの線形代数、時代とともに旬な領域が変化していまして、最近は二重数とか自動微分とかをイギリスの大学で勉強するようです。

おじさんの時代は二乗すると-1になる数はiしかなかったのに。
二乗すると-1になる数三つに増えてるし、近頃は二乗すると0になる二重数があるらしいです。素粒子みたくフェルミ的とかボソン的なんていうらしいです。
二重数の話はまた後ろに書くとして、まずは自動微分について。

自動微分とはプログラムで関数の値の計算をするとなんとその導関数の値も同時に計算できちゃうアルゴリズムというか理論です。

たとえばx=1でいうと
y=x^2を計算すると1ですが、同時にy'=2*xの答え2も計算できてしまう。

ただそれだけなんです。
手動で計算したほうがはやいじゃん!

と思っていたのですが、よく調べてみると、単純な数式ならば手動で微分すればよいんですが、Σとかがある複雑な式の導関数の計算ができたり、ニュートン法と組み合わせれば、逆関数がわからない複雑な方程式が解けたり、計算が高速にできたりします。

早い話が、条件はありますが方程式が高速に解けるのです。
このため、深層学習のとかでも使われていたりします。

この自動微分の計算ですが、二重数と関係があるようで、二重数の虚部というのか実部でない部分の計算と同じなのです。

つまり二重数で関数を計算すると実部が関数の値で、実部でない部分が関数を微分した値になります。


ほんとかよ!素粒子と深層学習が一緒なのかよ!
ということで、確かめてみました。

自動微分の理論からプログラミング
http://kivantium.hateblo.jp/entry/2016/03/25/010320

二重数の理論からプログラミング
http://qiita.com/skitaoka/items/b7d0b19e13a7c6832773

この二つのライブラリで計算値が一緒になるんですね。
あらーびっくり。