00001 #include "TArrow.h"
00002 #include "TEllipse.h"
00003 #include "TPaveLabel.h"
00004 #include "TCanvas.h"
00005 #include "TH2F.h"
00006 #include "TFile.h"
00007 #include "TString.h"
00008 #include "TDirectory.h"
00009 #include "TKey.h"
00010 #include "TText.h"
00011
00012 #include "tmvaglob.C"
00013
00014
00015
00016
00017 TFile* Network_GFile = 0;
00018
00019 static Int_t c_DarkBackground = TColor::GetColor( "#6e7a85" );
00020
00021 void draw_layer_labels( Int_t nLayers );
00022 void draw_layer ( TCanvas* c, TH2F* h, Int_t iHist, Int_t nLayers, Double_t maxWeight );
00023 void draw_synapse ( Double_t cx1, Double_t cy1, Double_t cx2, Double_t cy2,
00024 Double_t rad1, Double_t rad2, Double_t weightNormed );
00025 TString* get_var_names ( Int_t nVars );
00026
00027 Bool_t MovieMode = kFALSE;
00028
00029 void draw_network( TFile* f, TDirectory* d, const TString& hName = "weights_hist",
00030 Bool_t movieMode = kFALSE, const TString& epoch = "" )
00031 {
00032 Bool_t __PRINT_LOGO__ = kTRUE;
00033 Network_GFile = f;
00034
00035 MovieMode = movieMode;
00036 if (MovieMode) c_DarkBackground = TColor::GetColor( "#707F7F" );
00037
00038
00039 TStyle* TMVAStyle = gROOT->GetStyle("TMVA");
00040 Int_t canvasColor = TMVAStyle->GetCanvasColor();
00041 TMVAStyle->SetCanvasColor( c_DarkBackground );
00042
00043 Int_t titleFillColor = TMVAStyle->GetTitleFillColor();
00044 Int_t titleTextColor = TMVAStyle->GetTitleTextColor();
00045 Int_t borderSize = TMVAStyle->GetTitleBorderSize();
00046
00047 TMVAStyle->SetTitleFillColor( c_DarkBackground );
00048 TMVAStyle->SetTitleTextColor( TColor::GetColor( "#FFFFFF" ) );
00049 TMVAStyle->SetTitleBorderSize( 0 );
00050
00051 static Int_t icanvas = -1;
00052 Int_t ixc = 100 + (icanvas)*40;
00053 Int_t iyc = 0 + (icanvas+1)*20;
00054 if (MovieMode) ixc = iyc = 0;
00055 TString canvasnumber = Form( "c%i", icanvas );
00056 TString canvastitle = Form("Neural Network Layout for: %s", d->GetName());
00057 TCanvas* c = new TCanvas( canvasnumber, canvastitle,
00058 ixc, 0 + (icanvas+1)*20, 1000, 650 );
00059 icanvas++;
00060 TIter next = d->GetListOfKeys();
00061 TKey *key( 0 );
00062 Int_t numHists = 0;
00063
00064
00065 next.Reset();
00066 Double_t maxWeight = 0;
00067
00068 while ((key = (TKey*)next())) {
00069
00070 TClass *cl = gROOT->GetClass(key->GetClassName());
00071 if (!cl->InheritsFrom("TH2F")) continue;
00072
00073 TH2F* h = (TH2F*)key->ReadObj();
00074 if (!h) {
00075 cout << "Big troubles in \"draw_network\" (1)" << endl;
00076 exit(1);
00077 }
00078 if (TString(h->GetName()).Contains( hName )){
00079 numHists++;
00080
00081 Int_t n1 = h->GetNbinsX();
00082 Int_t n2 = h->GetNbinsY();
00083 for (Int_t i = 0; i < n1; i++) {
00084 for (Int_t j = 0; j < n2; j++) {
00085 Double_t weight = TMath::Abs(h->GetBinContent(i+1, j+1));
00086 if (maxWeight < weight) maxWeight = weight;
00087 }
00088 }
00089 }
00090 }
00091 if (numHists == 0) {
00092 cout << "Error: could not find histograms" << endl;
00093
00094 }
00095
00096
00097 next.Reset();
00098
00099
00100 Int_t count = 0;
00101 while ((key = (TKey*)next())) {
00102
00103
00104 TClass *cl = gROOT->GetClass(key->GetClassName());
00105 if (!cl->InheritsFrom("TH2F")) continue;
00106
00107
00108 TH2F* h = (TH2F*)key->ReadObj();
00109
00110 if (!h) {
00111 cout << "Big troubles in \"draw_network\" (2)" << endl;
00112 exit(1);
00113 }
00114
00115 if (TString(h->GetName()).Contains( hName )) {
00116
00117 draw_layer(c, h, count++, numHists+1, maxWeight);
00118 }
00119
00120
00121 }
00122 draw_layer_labels(numHists+1);
00123
00124
00125 if (MovieMode) {
00126 TText* t = new TText();
00127 t->SetTextSize( 0.04 );
00128 t->SetTextColor( 0 );
00129 t->SetTextAlign( 31 );
00130 t->DrawTextNDC( 1 - c->GetRightMargin(), 1 - c->GetTopMargin() - 0.033,
00131 Form( "Epoch: %s", epoch.Data() ) );
00132 }
00133
00134
00135 if (__PRINT_LOGO__) TMVAGlob::plot_logo();
00136
00137
00138 c->Update();
00139 if (MovieMode) {
00140
00141 TString dirname = "movieplots";
00142 TString foutname = dirname + "/" + hName;
00143 foutname.Resize( foutname.Length()-5 );
00144 foutname.ReplaceAll("epochmonitoring___","");
00145 foutname += ".gif";
00146
00147 cout << "storing file: " << foutname << endl;
00148 c->Print(foutname);
00149 c->Clear();
00150 delete c;
00151 }
00152 else {
00153 TString fname = "plots/network";
00154 TMVAGlob::imgconv( c, fname );
00155 }
00156
00157
00158 TMVAStyle->SetCanvasColor ( canvasColor );
00159 TMVAStyle->SetTitleFillColor ( titleFillColor );
00160 TMVAStyle->SetTitleTextColor ( titleTextColor );
00161 TMVAStyle->SetTitleBorderSize( borderSize );
00162
00163 }
00164
00165 void draw_layer_labels(Int_t nLayers)
00166 {
00167 const Double_t LABEL_HEIGHT = 0.032;
00168 const Double_t LABEL_WIDTH = 0.20;
00169 Double_t effWidth = 0.8*(1.0-LABEL_WIDTH)/nLayers;
00170 Double_t height = 0.8*LABEL_HEIGHT;
00171 Double_t margY = LABEL_HEIGHT - height;
00172
00173 for (Int_t i = 0; i < nLayers; i++) {
00174 TString label = Form("Layer %i", i);
00175 if (i == nLayers-1) label = "Output layer";
00176 Double_t cx = i*(1.0-LABEL_WIDTH)/nLayers+1.0/(2.0*nLayers)+LABEL_WIDTH;
00177 Double_t x1 = cx-0.8*effWidth/2.0;
00178 Double_t x2 = cx+0.8*effWidth/2.0;
00179 Double_t y1 = margY;
00180 Double_t y2 = margY + height;
00181
00182 TPaveLabel *p = new TPaveLabel(x1, y1, x2, y2, label+"", "br");
00183 p->SetFillColor(gStyle->GetTitleFillColor());
00184 p->SetTextColor(gStyle->GetTitleTextColor());
00185 p->SetFillStyle(1001);
00186 p->SetBorderSize( 0 );
00187 p->Draw();
00188 }
00189 }
00190
00191 void draw_input_labels(Int_t nInputs, Double_t* cy,
00192 Double_t rad, Double_t layerWidth)
00193 {
00194 const Double_t LABEL_HEIGHT = 0.04;
00195 const Double_t LABEL_WIDTH = 0.20;
00196 Double_t width = LABEL_WIDTH + (layerWidth-4*rad);
00197 Double_t margX = 0.01;
00198 Double_t effHeight = 0.8*LABEL_HEIGHT;
00199
00200 TString *varNames = get_var_names(nInputs);
00201 if (varNames == 0) exit(1);
00202
00203 TString input;
00204
00205 for (Int_t i = 0; i < nInputs; i++) {
00206 if (i != nInputs-1) input = varNames[i];
00207 else input = "Bias node";
00208 Double_t x1 = margX;
00209 Double_t x2 = margX + width;
00210 Double_t y1 = cy[i] - effHeight;
00211 Double_t y2 = cy[i] + effHeight;
00212
00213 TText* t = new TText();
00214 t->SetTextColor(gStyle->GetTitleTextColor());
00215 t->SetTextAlign(31);
00216 t->SetTextSize(LABEL_HEIGHT);
00217 if (i == nInputs-1) t->SetTextColor( TColor::GetColor( "#AFDCEC" ) );
00218 t->DrawText( x2, y1+0.018, input + " :");
00219 }
00220
00221 delete[] varNames;
00222 }
00223
00224 TString* get_var_names( Int_t nVars )
00225 {
00226 const TString directories[6] = { "InputVariables_NoTransform",
00227 "InputVariables_DecorrTransform",
00228 "InputVariables_PCATransform",
00229 "InputVariables_Id",
00230 "InputVariables_Norm",
00231 "InputVariables_Deco"};
00232
00233 TDirectory* dir = 0;
00234 for (Int_t i=0; i<6; i++) {
00235 dir = (TDirectory*)Network_GFile->Get( directories[i] );
00236 if (dir != 0) break;
00237 }
00238 if (dir==0) {
00239 cout << "*** Big troubles in macro \"network.C\": could not find directory for input variables, "
00240 << "and hence could not determine variable names --> abort" << endl;
00241 return 0;
00242 }
00243 dir->cd();
00244
00245 TString* vars = new TString[nVars];
00246 Int_t ivar = 0;
00247
00248
00249 TIter next(dir->GetListOfKeys());
00250 TKey* key = 0;
00251 while ((key = (TKey*)next())) {
00252 if (key->GetCycle() != 1) continue;
00253
00254 if (!TString(key->GetName()).Contains("__S") &&
00255 !TString(key->GetName()).Contains("__r") &&
00256 !TString(key->GetName()).Contains("Regression"))
00257 continue;
00258 if (TString(key->GetName()).Contains("target"))
00259 continue;
00260
00261
00262 TClass *cl = gROOT->GetClass(key->GetClassName());
00263 if (!cl->InheritsFrom("TH1")) continue;
00264 TH1 *sig = (TH1*)key->ReadObj();
00265 TString hname = sig->GetTitle();
00266
00267 vars[ivar] = hname; ivar++;
00268
00269 if (ivar > nVars-1) break;
00270 }
00271
00272 if (ivar != nVars-1) {
00273 cout << "*** Troubles in \"network.C\": did not reproduce correct number of "
00274 << "input variables: " << ivar << " != " << nVars << endl;
00275 }
00276
00277 return vars;
00278 }
00279
00280 void draw_activation(TCanvas* c, Double_t cx, Double_t cy,
00281 Double_t radx, Double_t rady, Int_t whichActivation)
00282 {
00283 TImage *activation = NULL;
00284
00285 switch (whichActivation) {
00286 case 0:
00287 activation = TImage::Open("sigmoid-small.png");
00288 break;
00289 case 1:
00290 activation = TImage::Open("line-small.png");
00291 break;
00292 default:
00293 cout << "Activation index " << whichActivation << " is not known." << endl;
00294 cout << "You messed up or you need to modify network.C to introduce a new "
00295 << "activation function (and image) corresponding to this index" << endl;
00296 }
00297
00298 if (activation == NULL) {
00299 cout << "Could not create an image... exit" << endl;
00300 return;
00301 }
00302
00303 activation->SetConstRatio(kFALSE);
00304
00305 radx *= 0.7;
00306 rady *= 0.7;
00307 TString name = Form("activation%f%f", cx, cy);
00308 TPad* p = new TPad(name+"", name+"", cx-radx, cy-rady, cx+radx, cy+rady);
00309
00310 p->Draw();
00311 p->cd();
00312
00313 activation->Draw();
00314 c->cd();
00315 }
00316
00317 void draw_layer(TCanvas* c, TH2F* h, Int_t iHist,
00318 Int_t nLayers, Double_t maxWeight)
00319 {
00320 const Double_t MAX_NEURONS_NICE = 12;
00321 const Double_t LABEL_HEIGHT = 0.03;
00322 const Double_t LABEL_WIDTH = 0.20;
00323 Double_t ratio = ((Double_t)(c->GetWindowHeight())) / c->GetWindowWidth();
00324 Double_t rad, cx1, *cy1, cx2, *cy2;
00325
00326
00327 rad = 0.04*650/c->GetWindowHeight();
00328
00329 Int_t nNeurons1 = h->GetNbinsX();
00330 cx1 = iHist*(1.0-LABEL_WIDTH)/nLayers + 1.0/(2.0*nLayers) + LABEL_WIDTH;
00331 cy1 = new Double_t[nNeurons1];
00332
00333 Int_t nNeurons2 = h->GetNbinsY();
00334 cx2 = (iHist+1)*(1.0-LABEL_WIDTH)/nLayers + 1.0/(2.0*nLayers) + LABEL_WIDTH;
00335 cy2 = new Double_t[nNeurons2];
00336
00337 Double_t effRad1 = rad;
00338 if (nNeurons1 > MAX_NEURONS_NICE)
00339 effRad1 = 0.8*(1.0-LABEL_HEIGHT)/(2.0*nNeurons1);
00340
00341 for (Int_t i = 0; i < nNeurons1; i++) {
00342 cy1[nNeurons1-i-1] = i*(1.0-LABEL_HEIGHT)/nNeurons1 + 1.0/(2.0*nNeurons1) + LABEL_HEIGHT;
00343
00344 if (iHist == 0) {
00345
00346 TEllipse *ellipse = new TEllipse( cx1, cy1[nNeurons1-i-1],
00347 effRad1*ratio, effRad1, 0, 360, 0 );
00348 ellipse->SetFillColor(TColor::GetColor( "#fffffd" ));
00349 ellipse->SetFillStyle(1001);
00350 ellipse->Draw();
00351
00352 if (i == 0) ellipse->SetLineColor(9);
00353
00354 if (nNeurons1 > MAX_NEURONS_NICE) continue;
00355
00356 Int_t whichActivation = 0;
00357 if (iHist==0 || iHist==nLayers-1 || i==0) whichActivation = 1;
00358 draw_activation(c, cx1, cy1[nNeurons1-i-1],
00359 rad*ratio, rad, whichActivation);
00360 }
00361 }
00362
00363 if (iHist == 0) draw_input_labels(nNeurons1, cy1, rad, (1.0-LABEL_WIDTH)/nLayers);
00364
00365 Double_t effRad2 = rad;
00366 if (nNeurons2 > MAX_NEURONS_NICE)
00367 effRad2 = 0.8*(1.0-LABEL_HEIGHT)/(2.0*nNeurons2);
00368
00369 for (Int_t i = 0; i < nNeurons2; i++) {
00370 cy2[nNeurons2-i-1] = i*(1.0-LABEL_HEIGHT)/nNeurons2 + 1.0/(2.0*nNeurons2) + LABEL_HEIGHT;
00371
00372 TEllipse *ellipse =
00373 new TEllipse(cx2, cy2[nNeurons2-i-1], effRad2*ratio, effRad2, 0, 360, 0);
00374 ellipse->SetFillColor(TColor::GetColor( "#fffffd" ));
00375 ellipse->SetFillStyle(1001);
00376 ellipse->Draw();
00377
00378 if (i == 0 && nNeurons2 > 1) ellipse->SetLineColor(9);
00379
00380 if (nNeurons2 > MAX_NEURONS_NICE) continue;
00381
00382 Int_t whichActivation = 0;
00383 if (iHist+1==0 || iHist+1==nLayers-1 || i==0) whichActivation = 1;
00384 draw_activation(c, cx2, cy2[nNeurons2-i-1], rad*ratio, rad, whichActivation);
00385 }
00386
00387 for (Int_t i = 0; i < nNeurons1; i++) {
00388 for (Int_t j = 0; j < nNeurons2; j++) {
00389 draw_synapse(cx1, cy1[i], cx2, cy2[j], effRad1*ratio, effRad2*ratio,
00390 h->GetBinContent(i+1, j+1)/maxWeight);
00391 }
00392 }
00393
00394 delete [] cy1;
00395 delete [] cy2;
00396 }
00397
00398 void draw_synapse(Double_t cx1, Double_t cy1, Double_t cx2, Double_t cy2,
00399 Double_t rad1, Double_t rad2, Double_t weightNormed)
00400 {
00401 const Double_t TIP_SIZE = 0.01;
00402 const Double_t MAX_WEIGHT = 8;
00403 const Double_t MAX_COLOR = 100;
00404 const Double_t MIN_COLOR = 60;
00405
00406 if (weightNormed == 0) return;
00407
00408
00409
00410 TArrow *arrow = new TArrow(cx1+rad1, cy1, cx2-rad2, cy2, TIP_SIZE, ">");
00411 arrow->SetFillColor(1);
00412 arrow->SetFillStyle(1001);
00413 arrow->SetLineWidth((Int_t)(TMath::Abs(weightNormed)*MAX_WEIGHT+0.5));
00414 arrow->SetLineColor((Int_t)((weightNormed+1.0)/2.0*(MAX_COLOR-MIN_COLOR)+MIN_COLOR+0.5));
00415 arrow->Draw();
00416 }
00417
00418
00419
00420 void network( TString fin = "TMVA.root", Bool_t useTMVAStyle = kTRUE )
00421 {
00422
00423 TMVAGlob::Initialize( useTMVAStyle );
00424
00425
00426 TFile* file = TMVAGlob::OpenFile( fin );
00427 TIter next(file->GetListOfKeys());
00428 TKey *key(0);
00429 while( (key = (TKey*)next()) ) {
00430 if (!TString(key->GetName()).BeginsWith("Method_MLP")) continue;
00431 if( ! gROOT->GetClass(key->GetClassName())->InheritsFrom("TDirectory") ) continue;
00432
00433 cout << "--- Found directory: " << ((TDirectory*)key->ReadObj())->GetName() << endl;
00434
00435 TDirectory* mDir = (TDirectory*)key->ReadObj();
00436
00437 TIter keyIt(mDir->GetListOfKeys());
00438 TKey *titkey;
00439 while((titkey = (TKey*)keyIt())) {
00440 if( ! gROOT->GetClass(titkey->GetClassName())->InheritsFrom("TDirectory") ) continue;
00441
00442 TDirectory* dir = (TDirectory *)titkey->ReadObj();
00443 dir->cd();
00444 TList titles;
00445 UInt_t ni = TMVAGlob::GetListOfTitles( dir, titles );
00446 if (ni==0) {
00447 cout << "No titles found for Method_MLP" << endl;
00448 return;
00449 }
00450 draw_network( file, dir );
00451 }
00452 }
00453
00454 return;
00455 }
00456