swh:1:snp:af87cd67498ef4fe47c76ed3e7caffe5b61facaf
Tip revision: 99d33abf07153edd6227af007b0dde0c7c4f99fd authored by Fons Rademakers on 11 October 2009, 20:37:38 UTC
tag patch release v5-24-00b.
tag patch release v5-24-00b.
Tip revision: 99d33ab
network.C
#include "tmvaglob.C"
// this macro prints out a neural network generated by MethodMLP graphically
// @author: Matt Jachowski, jachowski@stanford.edu
TFile* Network_GFile = 0;
static Int_t c_DarkBackground = TColor::GetColor( "#6e7a85" );
// input: - Input file (result from TMVA),
// - use of TMVA plotting TStyle
void network( TString fin = "TMVA.root", Bool_t useTMVAStyle = kTRUE )
{
// set style and remove existing canvas'
TMVAGlob::Initialize( useTMVAStyle );
// checks if file with name "fin" is already open, and if not opens one
TFile* file = TMVAGlob::OpenFile( fin );
Network_GFile = file;
TKey* mkey = TMVAGlob::FindMethod("MLP");
if (mkey==0) {
cout << "Could not locate directory MLP in file " << fin << endl;
return;
}
TDirectory *dir = (TDirectory *)mkey->ReadObj();
dir->cd();
TList titles;
UInt_t ni = TMVAGlob::GetListOfTitles( dir, titles );
if (ni==0) {
cout << "No titles found for Method_MLP" << endl;
return;
}
TIter nextTitle(&titles);
TKey *titkey;
TDirectory *titDir;
while ((titkey = TMVAGlob::NextKey(nextTitle,"TDirectory"))) {
titDir = (TDirectory *)titkey->ReadObj();
cout << "Drawing title: " << titDir->GetName() << endl;
draw_network(titDir);
}
}
void draw_network(TDirectory* d)
{
Bool_t __PRINT_LOGO__ = kTRUE;
// create canvas
TStyle* TMVAStyle = gROOT->GetStyle("TMVA"); // the TMVA style
Int_t canvasColor = TMVAStyle->GetCanvasColor(); // backup
TMVAStyle->SetCanvasColor( c_DarkBackground );
static icanvas = -1;
icanvas++;
TCanvas* c = new TCanvas( Form( "c%i", icanvas ), Form("Neural Network Layout for: %s", d->GetName()),
100 + (icanvas)*40, 0 + (icanvas+1)*20, 1000, 650 );
TIter next = d->GetListOfKeys();
TKey *key;
TString hName = "weights_hist";
Int_t numHists = 0;
// loop over all histograms with hName in name
while (key = (TKey*)next()) {
TClass *cl = gROOT->GetClass(key->GetClassName());
if (!cl->InheritsFrom("TH2F")) continue;
TH2F *h = (TH2F*)key->ReadObj();
if (TString(h->GetName()).Contains( hName )) {
numHists++;
}
}
// loop over all histograms with hName in name again
next.Reset();
Double_t maxWeight = 0;
// find max weight
while (key = (TKey*)next()) {
//cout << "Title: " << key->GetTitle() << endl;
TClass *cl = gROOT->GetClass(key->GetClassName());
if (!cl->InheritsFrom("TH2F")) continue;
TH2F* h = (TH2F*)key->ReadObj();
if (TString(h->GetName()).Contains( hName )){
Int_t n1 = h->GetNbinsX();
Int_t n2 = h->GetNbinsY();
for (Int_t i = 0; i < n1; i++) {
for (Int_t j = 0; j < n2; j++) {
Double_t weight = TMath::Abs(h->GetBinContent(i+1, j+1));
if (maxWeight < weight) maxWeight = weight;
}
}
}
}
// draw network
next.Reset();
Int_t count = 0;
while (key = (TKey*)next()) {
TClass *cl = gROOT->GetClass(key->GetClassName());
if (!cl->InheritsFrom("TH2F")) continue;
TH2F* h = (TH2F*)key->ReadObj();
if (TString(h->GetName()).Contains( hName )){
draw_layer(c, h, count++, numHists+1, maxWeight);
}
}
draw_layer_labels(numHists+1);
// ============================================================
if (__PRINT_LOGO__) TMVAGlob::plot_logo();
// ============================================================
c->Update();
TString fname = "plots/network";
TMVAGlob::imgconv( c, fname );
TMVAStyle->SetCanvasColor( canvasColor );
}
void draw_layer_labels(Int_t nLayers)
{
const Double_t LABEL_HEIGHT = 0.03;
const Double_t LABEL_WIDTH = 0.20;
Double_t effWidth = 0.8*(1.0-LABEL_WIDTH)/nLayers;
Double_t height = 0.8*LABEL_HEIGHT;
Double_t margY = LABEL_HEIGHT - height;
for (Int_t i = 0; i < nLayers; i++) {
TString label = Form("Layer %i", i);
Double_t cx = i*(1.0-LABEL_WIDTH)/nLayers+1.0/(2.0*nLayers)+LABEL_WIDTH;
Double_t x1 = cx-0.8*effWidth/2.0;
Double_t x2 = cx+0.8*effWidth/2.0;
Double_t y1 = margY;
Double_t y2 = margY + height;
TPaveLabel *p = new TPaveLabel(x1, y1, x2, y2, label+"", "br");
p->SetFillColor(gStyle->GetTitleFillColor());
p->SetFillStyle(1001);
p->Draw();
}
}
void draw_input_labels(Int_t nInputs, Double_t* cy,
Double_t rad, Double_t layerWidth)
{
const Double_t LABEL_HEIGHT = 0.03;
const Double_t LABEL_WIDTH = 0.20;
Double_t width = LABEL_WIDTH + (layerWidth-4*rad);
Double_t margX = 0.01;
Double_t effHeight = 0.8*LABEL_HEIGHT;
TString *varNames = get_var_names(nInputs);
if (varNames == 0) exit(1);
TString input;
for (Int_t i = 0; i < nInputs; i++) {
if (i != nInputs-1) input = varNames[i];
else input = "Bias node";
Double_t x1 = margX;
Double_t x2 = margX + width;
Double_t y1 = cy[i] - effHeight;
Double_t y2 = cy[i] + effHeight;
TPaveLabel *p = new TPaveLabel(x1, y1, x2, y2, input+"", "br");
p->SetFillColor(gStyle->GetTitleFillColor());
p->SetFillStyle(1001);
p->Draw();
if (i == nInputs-1) p->SetTextColor( TMVAGlob::c_NovelBlue );
}
delete[] varNames;
}
TString* get_var_names( Int_t nVars )
{
const TString directories[6] = { "InputVariables_NoTransform",
"InputVariables_DecorrTransform",
"InputVariables_PCATransform",
"InputVariables_Id",
"InputVariables_Norm",
"InputVariables_Deco"};
TDirectory* dir = 0;
for (Int_t i=0; i<6; i++) {
dir = (TDirectory*)Network_GFile->Get( directories[i] );
if (dir != 0) break;
}
if (dir==0) {
cout << "*** Big troubles in macro \"network.C\": could not find directory for input variables, "
<< "and hence could not determine variable names --> abort" << endl;
return 0;
}
cout << "--> go into directory: " << dir->GetName() << endl;
dir->cd();
TString* vars = new TString[nVars];
Int_t ivar = 0;
// loop over all objects in directory
TIter next(dir->GetListOfKeys());
TKey* key = 0;
while ((key = (TKey*)next())) {
if (key->GetCycle() != 1) continue;
if(!TString(key->GetName()).Contains("__S") &&
!TString(key->GetName()).Contains("__r")) continue;
// make sure, that we only look at histograms
TClass *cl = gROOT->GetClass(key->GetClassName());
if (!cl->InheritsFrom("TH1")) continue;
TH1 *sig = (TH1*)key->ReadObj();
TString hname = sig->GetTitle();
vars[ivar] = hname; ivar++;
if (ivar > nVars-1) break;
}
if (ivar != nVars-1) { // bias layer is also in nVars counts
cout << "*** Troubles in \"network.C\": did not reproduce correct number of "
<< "input variables: " << ivar << " != " << nVars << endl;
}
return vars;
// ------------- old way (not good) -------------
// TString fname = "weights/TMVAnalysis_MLP.weights.txt";
// ifstream fin( fname );
// if (!fin.good( )) { // file not found --> Error
// cout << "Error opening " << fname << endl;
// exit(1);
// }
// Int_t idummy;
// Float_t fdummy;
// TString dummy = "";
// // file header with name
// while (!dummy.Contains("#VAR")) fin >> dummy;
// fin >> dummy >> dummy >> dummy; // the rest of header line
// // number of variables
// fin >> dummy >> idummy;
// // at this point, we should have idummy == nVars
// // variable mins and maxes
// TString* vars = new TString[nVars];
// for (Int_t i = 0; i < idummy; i++) fin >> vars[i] >> dummy >> dummy >> dummy;
// fin.close();
// return vars;
}
void draw_activation(TCanvas* c, Double_t cx, Double_t cy,
Double_t radx, Double_t rady, Int_t whichActivation)
{
TImage *activation = NULL;
switch (whichActivation) {
case 0:
activation = TImage::Open("sigmoid-small.png");
break;
case 1:
activation = TImage::Open("line-small.png");
break;
default:
cout << "Activation index " << whichActivation << " is not known." << endl;
cout << "You messed up or you need to modify network.C to introduce a new "
<< "activation function (and image) corresponding to this index" << endl;
}
if (activation == NULL) {
cout << "Could not create an image... exit" << endl;
return;
}
activation->SetConstRatio(kFALSE);
radx *= 0.7;
rady *= 0.7;
TString name = Form("activation%f%f", cx, cy);
TPad* p = new TPad(name+"", name+"", cx-radx, cy-rady, cx+radx, cy+rady);
p->Draw();
p->cd();
activation->Draw();
c->cd();
}
void draw_layer(TCanvas* c, TH2F* h, Int_t iHist,
Int_t nLayers, Double_t maxWeight)
{
const Double_t MAX_NEURONS_NICE = 12;
const Double_t LABEL_HEIGHT = 0.03;
const Double_t LABEL_WIDTH = 0.20;
Double_t ratio = ((Double_t)(c->GetWindowHeight())) / c->GetWindowWidth();
Double_t rad, cx1, *cy1, cx2, *cy2;
// this is the smallest radius that will still display the activation images
rad = 0.04*650/c->GetWindowHeight();
Int_t nNeurons1 = h->GetNbinsX();
cx1 = iHist*(1.0-LABEL_WIDTH)/nLayers + 1.0/(2.0*nLayers) + LABEL_WIDTH;
cy1 = new Double_t[nNeurons1];
Int_t nNeurons2 = h->GetNbinsY();
cx2 = (iHist+1)*(1.0-LABEL_WIDTH)/nLayers + 1.0/(2.0*nLayers) + LABEL_WIDTH;
cy2 = new Double_t[nNeurons2];
Double_t effRad1 = rad;
if (nNeurons1 > MAX_NEURONS_NICE)
effRad1 = 0.8*(1.0-LABEL_HEIGHT)/(2.0*nNeurons1);
for (Int_t i = 0; i < nNeurons1; i++) {
cy1[nNeurons1-i-1] = i*(1.0-LABEL_HEIGHT)/nNeurons1 +
1.0/(2.0*nNeurons1) + LABEL_HEIGHT;
if (iHist == 0) {
TEllipse *ellipse
= new TEllipse(cx1, cy1[nNeurons1-i-1],
effRad1*ratio, effRad1, 0, 360, 0);
ellipse->SetFillColor(TColor::GetColor( "#fffffd" ));
ellipse->SetFillStyle(1001);
ellipse->Draw();
if (i == 0) ellipse->SetLineColor(9);
if (nNeurons1 > MAX_NEURONS_NICE) continue;
Int_t whichActivation = 0;
if (iHist==0 || iHist==nLayers-1 || i==0) whichActivation = 1;
draw_activation(c, cx1, cy1[nNeurons1-i-1],
rad*ratio, rad, whichActivation);
}
}
if (iHist == 0) draw_input_labels(nNeurons1, cy1, rad, (1.0-LABEL_WIDTH)/nLayers);
Double_t effRad2 = rad;
if (nNeurons2 > MAX_NEURONS_NICE)
effRad2 = 0.8*(1.0-LABEL_HEIGHT)/(2.0*nNeurons2);
for (Int_t i = 0; i < nNeurons2; i++) {
cy2[nNeurons2-i-1] = i*(1.0-LABEL_HEIGHT)/nNeurons2 + 1.0/(2.0*nNeurons2) + LABEL_HEIGHT;
TEllipse *ellipse =
new TEllipse(cx2, cy2[nNeurons2-i-1], effRad2*ratio, effRad2, 0, 360, 0);
ellipse->SetFillColor(TColor::GetColor( "#fffffd" ));
ellipse->SetFillStyle(1001);
ellipse->Draw();
if (i == 0 && nNeurons2 > 1) ellipse->SetLineColor(9);
if (nNeurons2 > MAX_NEURONS_NICE) continue;
Int_t whichActivation = 0;
if (iHist+1==0 || iHist+1==nLayers-1 || i==0) whichActivation = 1;
draw_activation(c, cx2, cy2[nNeurons2-i-1], rad*ratio, rad, whichActivation);
}
for (Int_t i = 0; i < nNeurons1; i++) {
for (Int_t j = 0; j < nNeurons2; j++) {
draw_synapse(cx1, cy1[i], cx2, cy2[j], effRad1*ratio, effRad2*ratio,
h->GetBinContent(i+1, j+1)/maxWeight);
}
}
delete[] cy1;
delete[] cy2;
}
void draw_synapse(Double_t cx1, Double_t cy1, Double_t cx2, Double_t cy2,
Double_t rad1, Double_t rad2, Double_t weightNormed)
{
const Double_t TIP_SIZE = 0.01;
const Double_t MAX_WEIGHT = 8;
const Double_t MAX_COLOR = 100; // red
const Double_t MIN_COLOR = 60; // blue
if (weightNormed == 0) return;
// gStyle->SetPalette(100, NULL);
TArrow *arrow = new TArrow(cx1+rad1, cy1, cx2-rad2, cy2, TIP_SIZE, ">");
arrow->SetFillColor(1);
arrow->SetFillStyle(1001);
arrow->SetLineWidth((Int_t)(TMath::Abs(weightNormed)*MAX_WEIGHT+0.5));
arrow->SetLineColor((Int_t)((weightNormed+1.0)/2.0*(MAX_COLOR-MIN_COLOR)+MIN_COLOR+0.5));
arrow->Draw();
}