2016-07-29 37 views
3

Ich benutze die Julia 0.4.6 derzeit in 64bit Debian Stretch ("testing"). Ich verwende es derzeit in einer 4-Core-4-GB-VM.Wie verwendet man Interpolationen auf SharedArray im Worker-Prozess, ohne dass jeder Prozess eine eigene Kopie der Daten erstellt?

Was ich im Grunde versuche zu tun ist, den Hauptprozess ein 3D SharedArray einzurichten, und dann parallel die Produktion eines 2D-Array von diesem 3D-Array über Worker-Prozesse abgeleitet. Wenn ich möchte, dass die Worker auf dieses Volume zugreifen (alles, da ich nicht vorhersagen kann, welche Bits sie tatsächlich brauchen), über eine Interpolation, dann habe ich Probleme mit der grassierenden Speichernutzung.

Hier ist ein minimal-Code demonstriert, was ich versuche zu tun ...

Zuerst wird eine Interpolation kostenlose Version:

# Initialize 1GByte of SharedArray 
volume=SharedArray(Float32,(512,512,1024)) # 1 GByte of shared data 
volume[:,:,:]=rand(Float32,(512,512,1024)) 

# Function to compute directly from array 
function test0() 
    image=SharedArray(Float32,(512,512)) 
    @sync @parallel for y=1:512 
    for x=1:512 
     image[x,y]=volume[x,y,512] 
    end 
    end 
    sdata(image) 
end 

println(mean(test0())) 

Das funktioniert gut, ob ich es ohne Arbeiter oder -p ausführen 2 , -p 4, -p 8 oder -p 16 (es gibt nicht viel Leistungsverbesserung, aber bedenken Sie, dass dies nur ein Modell für etwas ist, das in jeder Iteration viel mehr berechnet).

jedoch diese Version:

using Interpolations 

# Function to compute via interpolator 
function test1() 
    sampler=interpolate(volume,BSpline(Linear()),OnGrid()) 

    image=SharedArray(Float32,(512,512)) 

    @sync @parallel for i=1:512*512 
    x,y=ind2sub((512,512),i) 
    image[x,y]=sampler[x,y,512] 
    end 
    sdata(image) 
end 

println(mean(test1())) 

startet das System mit -p Swapping 2 und -p 4 die mit OutOfMemoryError s Abschluss Arbeiter.

Was ich raten ist, dass die Serialisierung des Interpolators auf die Arbeitsprozesse aus den Augen verliert es auf einem SharedArray sitzen und kopiert nur die Daten Großhandel in eine nicht freigegebene Kopie in jedem Arbeiter.

Meine Frage ist: Was kann ich tun, um dies zu verbessern? Gibt es ein besseres Muster für das, was ich hier versuche, oder eine schlaue Verwendung von @<something>, die dazu führt, dass jeder Arbeiter das Shared-Array anstelle seiner eigenen Kopie interpoliert?

Update:

Dieser Ansatz scheint sinnvollerweise die Schaffung eines Interpolations-Objekts in jeden Arbeitsprozeß zu schieben:

function test(volume) 

    image=SharedArray(Float32,(512,512)) 

    sampler=Nullable() 

    @sync @parallel for i=1:512*512 
    x,y=ind2sub((512,512),i) 
    if isnull(sampler) 
     warn(STDERR,"Allocating sampler...") 
     sampler=Nullable(Interpolations.interpolate(sdata(volume),Interpolations.BSpline(Interpolations.Linear()),Interpolations.OnGrid())) 
     warn(STDERR,"...allocated sampler") 
    end 
    image[x,y]=get(sampler)[x,y,512] 
    end 
    sdata(image) 
end 

... es leidet jedoch noch aus genau dem gleichen Problem und mit mehr als ein paar Worker-Prozesse beginnen mit dem Tauschen oder schaffen die Sampler aufgrund von Speichererschöpfung nicht.

Eine nähere Betrachtung des Interpolations.jl Code schlägt vor, dass es im Allgemeinen erwartet, das gegebene Array zu padieren und/oder vorzufiltern (was offensichtlich bedeutet, dass es eine Kopie nimmt) ... aber ich kann Julia noch nicht gut genug lesen, um zu verstehen ob BSpline(Linear()) eine Chance hat, die erstellten Kopien zu umgehen und den enormen Overhead pro Prozessspeicher zu vermeiden. Ich sehe, dass die Quadratische Interpolation die faszinierende Option bietet, dass Vorfilterung "InPlace" durchgeführt wird, aber ich habe dies noch nicht weiter untersucht (ein signifikantes Problem scheint alle die Arbeiter zu vermeiden, die versuchen, die geteilten Daten zu filtern).

+2

Mein Bauchgefühl ist hier, dass Sie besser mit 'remotecall()', '@ spawn' oder dergleichen sein würden. Ich habe herausgefunden, dass '@parallel' in Bezug auf die Handhabung der Datenbewegung manchmal ein wenig skizzenhaft ist, und daher können einige der anderen parallelen Funktionen in Julia, die Ihnen eine direktere Kontrolle darüber geben, was vor sich geht, besser sein. Ich werde später oder morgen nachschauen, wenn Sie und/oder jemand anderes es vorher nicht ausgearbeitet hat. –

Antwort

2

Apparently Die Lösung ist die Verwendung der interpolate! Version von interpolieren.Dies funktioniert gut, mit so viele Arbeitsprozessen, wie ich an ihn werfen:

using Interpolations 

# Function to compute via interpolator 
function test(volume) 

    image=SharedArray(Float32,(512,512)) 

    sampler=interpolate!(
    volume, 
    Interpolations.BSpline(Interpolations.Linear()), 
    Interpolations.OnGrid() 
) 

    @sync @parallel for i=1:512*512 
    x,y=ind2sub((512,512),i) 
    image[x,y]=sampler[x,y,512] 
    end 
    sdata(image) 
end 

# Initialize 1GByte of SharedArray 
volume=SharedArray(Float32,(512,512,1024)) # 1 GByte of shared data 
volume[:,:,:]=rand(Float32,(512,512,1024)) 

println(mean(test(volume))) 

Es gibt auch ein prefilter!, die es Hinweise möglich sein kann, die höhere Ordnung Interpolationsverfahren zu ähnlich zu verwenden, aber ein lineare Interpolation ist gut genug für meine Zwecke .

+0

Super, ich bin so froh zu hören, dass es eine Lösung dafür gibt! –