Beam'de Gizlilik ile Özel İstatistikleri Hesaplama

1. Giriş

Toplu istatistiklerin, istatistiklerin oluştuğu bireyler hakkında bilgi sızdırmadığını düşünebilirsiniz. Bununla birlikte, bir saldırganın toplu istatistik üzerinden veri kümesindeki bireyler hakkındaki hassas bilgileri öğrenmesinin birçok yolu vardır.

Şahısların güvenliğini sağlamak Privacy on Beam'den diferansiyel şekilde özel toplamaları kullanarak nasıl özel istatistikler oluşturabileceğinizi öğreneceksiniz. Kiriş üzerinde gizlilik, Apache Beam ile çalışan diferansiyel bir gizlilik çerçevesidir.

"Özel" derken neyi kastediyoruz?

"Özel" kelimesini kullanırken Bu Codelab boyunca, çıktının, verilerdeki kişilerle ilgili gizli bilgileri sızdırmayacak şekilde üretildiğini kastediyoruz. Bunu güçlü bir gizlilik kavramı olan diferansiyel gizlilikle yapabiliriz. Anonimleştirme, kullanıcı gizliliğini korumak için birden fazla kullanıcıdan veri toplama işlemidir. Tüm anonimleştirme yöntemleri toplama kullanır, ancak tüm toplama yöntemleri anonimleştirme sağlamaz. Diferansiyel gizlilik ise bilgi sızıntısı ve gizlilikle ilgili ölçülebilir garantiler sağlar.

2. Diferansiyel gizliliğe genel bakış

Diferansiyel gizliliği daha iyi anlamak için basit bir örneğe bakalım.

Bu çubuk grafikte, küçük bir restoranın belirli bir akşamdaki yoğunluğu gösterilmektedir. Birçok konuk saat 19:00'da geliyor ve saat 01:00'de restoran tamamen boş:

a43dbf3e2c6de596.png

Yararlı görünüyor.

Önemli bir fark var. Yeni bir konuk geldiğinde bu durum çubuk grafikte hemen gösterilir. Grafiğe bakın: Yeni bir konuğun olduğu ve bu konuğun yaklaşık 01:00'de geldiği anlaşılıyor:

bda96729e700a9dd.png

Bu, gizlilik açısından pek iyi bir fikir değil. Gerçekten anonimleştirilmiş istatistikler, bireysel katkıları ifşa etmemelidir. Bu iki grafiği yan yana göstermek daha da belirgin hale geliyor: Turuncu çubuk grafikte ekstradan bir davetli daha var ve yaklaşık 01:00'de geliyor:

d562ddf799288894.png

Pek iyi değil. Ne yaparız?

Rastgele gürültü ekleyerek çubuk grafiklerin doğruluk düzeyini düşüreceğiz.

Aşağıdaki iki çubuk grafiğe bakın. Tamamen doğru olmasa da yine de yararlıdır ve bireysel katkıları açıklamaz. Güzel!

838a0293cd4fcfe3.gif

Diferansiyel gizlilik, bireysel katkıları maskelemek için doğru miktarda rastgele gürültü eklemektir.

Analizlerimiz biraz fazla basitleştirildi. Diferansiyel gizliliği doğru şekilde uygulamak daha karmaşıktır ve uygulamanın son derece beklenmedik bazı incelikleri vardır. Kriptografiye benzer şekilde, kendi diferansiyel gizlilik uygulamanızı oluşturmak çok iyi bir fikir olmayabilir. Kendi çözümünüzü uygulamak yerine Beam'de gizlilik özelliğini kullanabilirsiniz. Kendi diferansiyel gizliliğinizi kullanmayın.

Bu codelab'de, Privacy on Beam'i kullanarak diferansiyel gizli analizin nasıl yapılacağını göstereceğiz.

3. Privacy on Beam indiriliyor

Tüm ilgili kodlar ve grafikler bu dokümanda bulunduğundan, codelab'i izleyebilmek için Beam'de Privacy uygulamasını indirmeniz gerekmez. Bununla birlikte, kodla oynamak, kodu kendiniz çalıştırmak veya daha sonra Beam'de Privacy'yi kullanmak için indirmek isterseniz aşağıdaki adımları uygulayarak bu işlemi gerçekleştirebilirsiniz.

Bu codelab'in, kitaplığın 1.1.0 sürümü için olduğunu unutmayın.

İlk olarak Privacy on Beam'i indirin:

https://github.com/google/differential-privacy/archive/refs/tags/v1.1.0.tar.gz

Dilerseniz GitHub deposunu klonlayabilirsiniz:

git clone --branch v1.1.0 https://github.com/google/differential-privacy.git

Beam'de gizlilik, üst düzey privacy-on-beam/ dizininde yer alıyor.

Bu codelab'in kodu ve veri kümesi, privacy-on-beam/codelab/ dizinindedir.

Ayrıca, bilgisayarınızda Bazel'in yüklü olması gerekir. İşletim sisteminize yönelik yükleme talimatlarını Bazel web sitesinde bulun.

4. Saat başına ziyaret sayısı hesaplanıyor

Bir restoran sahibi olduğunuzu ve popüler ziyaret saatlerini paylaşmak gibi restoranınızla ilgili bazı istatistikleri paylaşmak istediğinizi varsayalım. Neyse ki, Diferansiyel Gizlilik ve Anonimleştirme hakkında bilgi sahibisiniz. Dolayısıyla, bunu herhangi bir ziyaretçi hakkında bilgi sızdırmayacak şekilde yapmak istiyorsunuz.

Bu örnek için belirlenen kod codelab/count.go dilindedir.

Belirli bir Pazartesi günü restoranınıza yapılan ziyaretleri içeren örnek bir veri kümesi yükleyerek başlayalım. Bu kod, codelab'in amaçları açısından önemli değildir ancak o kodu codelab/main.go, codelab/utils.go ve codelab/visit.go üzerinde inceleyebilirsiniz.

Ziyaretçi Kimliği

Girilen saat

Harcanan süre (dk.)

Harcanan para (avro)

1

09:30:00

26

24

2

11:54:00

53

17

3

13:05:00

81

33

İlk olarak aşağıdaki kod örneğinde Beam'i kullanarak restoranınıza yapılan ziyaretlerin özel olmayan bir çubuk grafiğini oluşturacaksınız. Scope, ardışık düzenin bir temsilidir. Veriler üzerinde yaptığımız her yeni işlem Scope bölümüne eklenir. CountVisitsPerHour, bir Scope ve bir ziyaret koleksiyonunu alır. Bu koleksiyon, Beam'de PCollection olarak gösterilir. Koleksiyonda extractVisitHour işlevini uygulayarak her ziyaretin saatini ayıklar. Daha sonra, her saatin tekrarlarını sayar ve bunu döndürür.

func CountVisitsPerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("CountVisitsPerHour")
    visitHours := beam.ParDo(s, extractVisitHourFn, col)
    visitsPerHour := stats.Count(s, visitHours)
    return visitsPerHour
}

func extractVisitHourFn(v Visit) int {
    return v.TimeEntered.Hour()
}

Bu işlem, geçerli dizinde count.png olarak güzel bir çubuk grafik oluşturur (bazel run codelab -- --example="count" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/count.csv --output_chart_file=$(pwd)/count.png öğesini çalıştırarak):

a179766795d4e64a.png

Bir sonraki adım, ardışık düzeninizi ve çubuk grafiğinizi gizli bir sütuna dönüştürmektir. Bunu aşağıdaki şekilde yaparız.

İlk olarak, PrivatePCollection<V> almak için PCollection<V> numaralı telefondan MakePrivateFromStruct adlı kuruluşu arayın. PCollection girişinin bir struct koleksiyonu olması gerekir. MakePrivateFromStruct için giriş olarak bir PrivacySpec ve idFieldPath girmemiz gerekiyor.

spec := pbeam.NewPrivacySpec(epsilon, delta)
pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

PrivacySpec, verileri anonimleştirmek için kullanmak istediğimiz diferansiyel gizlilik parametrelerini (epsilon ve delta) barındıran bir yapıdır. (Şu an için bu konular hakkında endişelenmenize gerek yok. Bunlar hakkında daha fazla bilgi edinmek isterseniz ilerleyen zamanlarda isteğe bağlı bir bölüm de oluşturacağız.)

idFieldPath, struct (bizim örneğimizde Visit) içindeki kullanıcı tanımlayıcısı alanının yoludur. Burada, ziyaretçilerin kullanıcı tanımlayıcısı Visit öğesinin VisitorID alanıdır.

Ardından, stats.Count() yerine pbeam.Count() adını veriyoruz. pbeam.Count(), giriş olarak, çıkışın doğruluğunu etkileyen MaxValue gibi parametreleri barındıran bir CountParams struct'ı alır.

visitsPerHour := pbeam.Count(s, visitHours, pbeam.CountParams{
    // Visitors can visit the restaurant once (one hour) a day
    MaxPartitionsContributed: 1,
    // Visitors can visit the restaurant once within an hour
    MaxValue:                 1,
})

Benzer şekilde MaxPartitionsContributed, bir kullanıcının katkıda bulunabileceği farklı ziyaret saatini sınırlar. Onların restoranı günde en fazla bir kez ziyaret etmelerini bekliyoruz (veya gün içinde birden çok kez ziyaret etmeleri önemsemiyor). Bu nedenle, sayıyı da 1 olarak ayarladık. İsteğe bağlı bir bölümde, bu parametrelerden daha ayrıntılı bir şekilde bahsedeceğiz.

MaxValue, tek bir kullanıcının saydığımız değerlere kaç kez katkıda bulunabileceğini sınırlar. Bu örnekte, saydığımız değerler ziyaret saatleridir ve kullanıcının restoranı yalnızca bir kez ziyaret etmesini bekleriz (veya bir saat içinde birden çok kez ziyaret etmesi ilgimizi göstermez). Bu nedenle, bu parametreyi 1 olarak ayarlarız.

Sonuç olarak, kodunuz aşağıdaki gibi görünür:

func PrivateCountVisitsPerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateCountVisitsPerHour")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, delta)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    visitHours := pbeam.ParDo(s, extractVisitHourFn, pCol)
    visitsPerHour := pbeam.Count(s, visitHours, pbeam.CountParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Visitors can visit the restaurant once within an hour
        MaxValue:                 1,
    })
    return visitsPerHour
}

Diferansiyel gizli istatistik için benzer bir çubuk grafik (count_dp.png) görüyoruz (önceki komut hem gizli olmayan hem de özel ardışık düzenleri çalıştırır):

d6a0ace1acd3c760.png

Tebrikler! Diferansiyel gizliliğe sahip ilk istatistiğinizi hesapladınız.

Kodu çalıştırdığınızda gördüğünüz çubuk grafik bundan farklı olabilir. Sorun değil. Diferansiyel gizlilikteki gürültü nedeniyle, kodu her çalıştırdığınızda farklı bir çubuk grafik görüntülenir. Ancak, bunların, elimizdeki gizli olmayan orijinal çubuk grafiğine daha çok veya daha az benzediğini görebilirsiniz.

Ardışık düzenin birden çok kez tekrar çalıştırılmamasının gizlilik garantileri açısından çok önemli olduğunu lütfen unutmayın (örneğin, daha iyi görünen bir çubuk grafik elde etmek için). Ardışık düzenlerinizi neden yeniden çalıştırmamanız gerektiğinin nedeni "Birden Çok İstatistiği Hesaplama" bölümünde açıklanmıştır. bölümüne ekleyin.

5. Herkese Açık Bölümleri Kullanma

Önceki bölümde, bazı bölümler (ör. saat) için tüm ziyaretleri (verileri) çıkardığımızı fark etmiş olabilirsiniz.

d7fbc5d86d91e54a.png

Bunun nedeni, bölüm seçimi/eşiğidir. Çıktı bölümlerinin varlığı kullanıcı verilerine bağlı olduğunda diferansiyel gizlilik garantilerini sağlamak açısından önemli bir adımdır. Böyle bir durumda, çıkışta sadece bir bölümün mevcut olması, verilerdeki bireysel bir kullanıcının varlığını sızdırabilir (Bunun gizliliği neden ihlal ettiğine dair açıklama için bu blog yayınına bakın). Bunu önlemek için Beam on Beam yalnızca yeterli sayıda kullanıcı bulunan bölümleri tutar.

Çıkış bölümleri listesi gizli kullanıcı verilerine bağlı olmadığında (ör. herkese açık bilgiler olduğunda) bu bölüm seçimi adımına ihtiyacımız olmaz. Restoran örneğimiz için de durum böyledir: Restoranın çalışma saatlerini biliyoruz (9:00 - 21:00).

Bu örnek için belirlenen kod codelab/public_partitions.go dilindedir.

9 ile 21 arasında saatlerden oluşan bir PCollection oluşturacağız (hariç) ve bunu CountParams öğesinin PublicPartitions alanına gireceğiz:

func PrivateCountVisitsPerHourWithPublicPartitions(s beam.Scope,
    col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateCountVisitsPerHourWithPublicPartitions")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    visitHours := pbeam.ParDo(s, extractVisitHourFn, pCol)
    visitsPerHour := pbeam.Count(s, visitHours, pbeam.CountParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Visitors can visit the restaurant once within an hour
        MaxValue:                 1,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })
    return visitsPerHour
}

Yukarıda olduğu gibi, genel bölümlendirmeleri ve Laplace Gürültüsü (varsayılan) kullanıyorsanız deltanın 0 değerine ayarlanabileceğini unutmayın.

Ardışık düzeni herkese açık bölümlendirmelerle (bazel run codelab -- --example="public_partitions" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/public_partitions.csv --output_chart_file=$(pwd)/public_partitions.png ile) çalıştırdığımızda (public_partitions_dp.png):

7c950fbe99fec60a.png

Gördüğünüz gibi, daha önce herkese açık bölümler olmadan bıraktığımız 9, 10 ve 16. bölümleri artık koruyoruz.

Herkese açık bölümlerin kullanılması hem daha fazla bölüm saklamanızı sağlar hem de gizlilik bütçesi harcanmaması nedeniyle herkese açık bölümlerin kullanılmadığı durumlara kıyasla her bölüme yaklaşık yarı yarıya daha fazla gürültü ekler. Örneğin epsilon & delta, bölüm seçiminde. Bu nedenle, ham ve gizli sayılar arasındaki fark önceki çalıştırmaya göre biraz daha azdır.

Herkese açık bölümleri kullanırken unutulmaması gereken iki önemli nokta vardır:

  1. Ham verilerden bölüm listesi oluştururken dikkatli olun: bunu diferansiyel gizlilikle (ör. Kullanıcı verilerindeki tüm bölümlerin listesini okumanız yeterlidir. Ardışık düzeniniz artık diferansiyel gizlilik garantileri sağlamaz. Bunu nasıl diferansiyel gizlilikle yapabileceğinizle ilgili bilgi için aşağıdaki gelişmiş bölümü inceleyin.
  2. Herkese açık bölümlerden bazılarına ait veri (ör. ziyaretler) yoksa diferansiyel gizliliği korumak için bu bölümlere gürültü uygulanır. Örneğin, 0 ile 24 arasında (9 ve 21 yerine) saatleri kullandıysak saatlerin tümü gürültü olarak gösterilir ve hiç ziyaret olmadığında bazı ziyaretler gösterilebilir.

(Gelişmiş) Verilerden Bölüm Türetme

Aynı ardışık düzende herkese açık olmayan çıkış bölümleriyle aynı listeyle birden fazla toplama çalıştırıyorsanız SelectPartitions() kullanarak ve her toplama işlemine bölümleri PublicPartition girişi olarak sağlayarak bölümlerin listesini türetebilirsiniz. Bu hem gizlilik açısından güvenlidir hem de tüm ardışık düzen için bölüm seçiminde yalnızca bir kez gizlilik bütçesi kullanmanız sayesinde daha az gürültü eklemenize olanak tanır.

6. Ortalama konaklama süresi hesaplanıyor

Öğelerin diferansiyel gizlilikle nasıl sayılacağını artık bildiğimize göre, hesaplama araçlarını inceleyelim. Daha açık belirtmek gerekirse, artık ziyaretçilerin ortalama konaklama süresini hesaplıyoruz.

Bu örnek için belirlenen kod codelab/mean.go dilindedir.

Normalde, konaklama sürelerinin gizli olmayan ortalamasını hesaplamak için, gelen ziyaretleri PCollection, K ziyaret saati, V ise ziyaretçinin restoranda geçirdiği süreyi PCollection<K,V> değerine dönüştüren bir ön işleme adımıyla stats.MeanPerKey() kullanırız.

func MeanTimeSpent(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("MeanTimeSpent")
    hourToTimeSpent := beam.ParDo(s, extractVisitHourAndTimeSpentFn, col)
    meanTimeSpent := stats.MeanPerKey(s, hourToTimeSpent)
    return meanTimeSpent
}

func extractVisitHourAndTimeSpentFn(v Visit) (int, int) {
    return v.TimeEntered.Hour(), v.MinutesSpent
}

Bu işlem, geçerli dizinde mean.png olarak güzel bir çubuk grafik oluşturur (bazel run codelab -- --example="mean" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/mean.csv --output_chart_file=$(pwd)/mean.png öğesini çalıştırarak):

bc2df28bf94b3721.png

Bunu diferansiyel gizli yapmak için, PCollection öğesini tekrar PrivatePCollection biçimine dönüştürür ve stats.MeanPerKey() yerine pbeam.MeanPerKey() ekleriz. Count parametresine benzer şekilde, doğruluğu etkileyen MinValue ve MaxValue gibi bazı parametreleri barındıran MeanParams var. MinValue ve MaxValue, her kullanıcının her anahtara yaptığı katkı için sahip olduğumuz sınırları temsil eder.

meanTimeSpent := pbeam.MeanPerKey(s, hourToTimeSpent, pbeam.MeanParams{
    // Visitors can visit the restaurant once (one hour) a day
    MaxPartitionsContributed:     1,
    // Visitors can visit the restaurant once within an hour
    MaxContributionsPerPartition: 1,
    // Minimum time spent per user (in mins)
    MinValue:                     0,
    // Maximum time spent per user (in mins)
    MaxValue:                     60,
})

Bu durumda, her anahtar bir saati, değerler ise ziyaretçilerin harcadığı süreyi temsil eder. Ziyaretçilerin restoranda 0 dakikadan az zaman geçirmesini beklemediğimiz için MinValue değerini 0 olarak ayarladık. MaxValue değerini 60 olarak ayarladık. Yani, bir ziyaretçi 60 dakikadan fazla zaman geçirdiyse, bu kullanıcı 60 dakika geçirmiş gibi davranırız.

Sonuç olarak, kodunuz aşağıdaki gibi görünür:

func PrivateMeanTimeSpent(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateMeanTimeSpent")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    hourToTimeSpent := pbeam.ParDo(s, extractVisitHourAndTimeSpentFn, pCol)
    meanTimeSpent := pbeam.MeanPerKey(s, hourToTimeSpent, pbeam.MeanParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed:     1,
        // Visitors can visit the restaurant once within an hour
        MaxContributionsPerPartition: 1,
        // Minimum time spent per user (in mins)
        MinValue:                     0,
        // Maximum time spent per user (in mins)
        MaxValue:                     60,
        // Visitors only visit during work hours
        PublicPartitions:             hours,
    })
    return meanTimeSpent
}

Diferansiyel gizli istatistik için benzer bir çubuk grafik (mean_dp.png) görüyoruz (önceki komut hem gizli olmayan hem de özel ardışık düzenleri çalıştırır):

e8ac6a9bf9792287.png

Yine sayıma benzer şekilde, bu diferansiyel gizli bir işlem olduğundan, onu her çalıştırdığımızda farklı sonuçlar alırız. Ancak, konaklama süreleri arasındaki farkın gerçek sonuçtan çok da uzak olmadığını görebilirsiniz.

7. Saat başına gelir hesaplaması

Göz atabileceğimiz bir başka ilginç istatistik ise, gün boyunca saatlik gelirdir.

Bu örnek için belirlenen kod codelab/sum.go dilindedir.

Yine gizli olmayan sürümle başlayalım. Sahte veri kümemizde bazı ön işlemelerle bir PCollection<K,V> oluşturabiliriz. Burada K ziyaret saati, V ise ziyaretçinin restoranda harcadığı paradır: Özel olmayan bir saat başına geliri hesaplamak için stats.SumPerKey() kodunu çağırarak ziyaretçilerin harcadıkları tüm parayı toplamamız yeterlidir:

func RevenuePerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("RevenuePerHour")
    hourToMoneySpent := beam.ParDo(s, extractVisitHourAndMoneySpentFn, col)
    revenues := stats.SumPerKey(s, hourToMoneySpent)
    return revenues
}

func extractVisitHourAndMoneySpentFn(v Visit) (int, int) {
    return v.TimeEntered.Hour(), v.MoneySpent
}

Bu işlem, geçerli dizinde sum.png olarak güzel bir çubuk grafik oluşturur (bazel run codelab -- --example="sum" --input_file=$(pwd)/day_data.csv --output_stats_file=$(pwd)/sum.csv --output_chart_file=$(pwd)/sum.png öğesini çalıştırarak):

548619173fad0c9a.png

Bunu diferansiyel gizli yapmak için, PCollection öğesini tekrar PrivatePCollection biçimine dönüştürür ve stats.SumPerKey() yerine pbeam.SumPerKey() ekleriz. Count ve MeanPerKey örneğine benzer şekilde, MinValue ve MaxValue gibi doğruluğu etkileyen bazı parametreleri barındıran SumParams var.

revenues := pbeam.SumPerKey(s, hourToMoneySpent, pbeam.SumParams{
    // Visitors can visit the restaurant once (one hour) a day
    MaxPartitionsContributed: 1,
    // Minimum money spent per user (in euros)
    MinValue:                 0,
    // Maximum money spent per user (in euros)
    MaxValue:                 40,
})

Bu durumda MinValue ve MaxValue, her ziyaretçinin harcadığı para miktarı için belirlenen sınırları temsil eder. Ziyaretçilerin restoranda 0 avrodan az harcama yapmasını beklemediğimiz için MinValue değerini 0 olarak ayarladık. MaxValue değerini 40 olarak belirledik. Örneğin, bir ziyaretçi 40 avrodan fazla harcama yaparsa 40 avro harcamış gibi davranırız.

Sonuç olarak, kod aşağıdaki gibi görünür:

func PrivateRevenuePerHour(s beam.Scope, col beam.PCollection) beam.PCollection {
    s = s.Scope("PrivateRevenuePerHour")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    hourToMoneySpent := pbeam.ParDo(s, extractVisitHourAndMoneySpentFn, pCol)
    revenues := pbeam.SumPerKey(s, hourToMoneySpent, pbeam.SumParams{
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Minimum money spent per user (in euros)
        MinValue:                 0,
        // Maximum money spent per user (in euros)
        MaxValue:                 40,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })
    return revenues
}

Diferansiyel gizli istatistik için benzer bir çubuk grafik (sum_dp.png) görüyoruz (önceki komut hem gizli olmayan hem de özel ardışık düzenleri çalıştırır):

46c375e874f3e7c4.png

Sayı ve ortalama işlemlerine benzer şekilde, bu diferansiyel gizli bir işlem olduğundan onu her çalıştırdığımızda farklı sonuçlar alırız. Ancak diferansiyel gizli sonucun, saatlik gerçek gelire çok yakın olduğunu görebilirsiniz.

8. Birden çok istatistik hesaplama

Çoğu zaman, sayım, ortalama ve toplam metriklerinde yaptığınız gibi, aynı temel veriler üzerinden birden çok istatistiği hesaplamak isteyebilirsiniz. Bunu tek bir Işın ardışık düzeninde ve tek bir ikili programda yapmak genellikle daha temiz ve daha kolaydır. Bunu Privacy on Beam ile de yapabilirsiniz. Dönüşümlerinizi ve hesaplamalarınızı çalıştırmak için tek bir ardışık düzen yazabilir ve tüm ardışık düzen için tek bir PrivacySpec kullanabilirsiniz.

Bunu tek bir PrivacySpec ile yapmak daha kullanışlı olmasının yanı sıra gizlilik açısından da daha iyidir. PrivacySpec ürününe sağladığımız epsilon ve delta parametrelerini hatırlıyorsanız bunlar, gizlilik bütçesi adı verilen bir şeyi temsil eder. Bu parametreler, temel verilerdeki kullanıcıların gizliliğinin ne kadarının sızdırıldığının ölçümüdür.

Gizlilik bütçesinin katkılara dayalı olduğu unutulmamalıdır: Tek seferde belirli bir epsilon £ ve delta 5 değeri içeren ardışık düzen çalıştırırsanız (£,Δ) bir bütçe harcıyorsunuz demektir. Denemeyi ikinci kez çalıştırırsanız toplamda (2\, 2Δ) tutarında bütçe harcamış olursunuz. Benzer şekilde, (£, teşvik) tutarında bir PrivacySpec (ve art arda bir gizlilik bütçesi) ile birden fazla istatistik hesaplarsanız toplam (2£, 2Δ) tutarında bir bütçe harcamış olursunuz. Bu durum, gizlilik garantilerini azalttığınız anlamına gelir.

Bu durumu atlatmak için, aynı temel veriler üzerinden birden fazla istatistik hesaplamak istediğinizde, kullanmak istediğiniz toplam bütçeyle tek bir PrivacySpec kullanmanız gerekir. Ardından her toplama için kullanmak istediğiniz epsilon ve deltayı belirtmeniz gerekir. En sonunda, aynı genel gizlilik garantisine sahip olursunuz. Ancak belirli bir toplamanın epsilon ve delta değeri ne kadar yüksek olursa doğruluğu da o kadar yüksek olur.

Bunu uygulamalı olarak görmek için, daha önce ayrı ayrı hesapladığımız üç istatistiği (sayı, ortalama ve toplam) tek bir ardışık düzende hesaplayabiliriz.

Bu örnek için belirlenen kod codelab/multiple.go dilindedir. Toplam bütçeyi (£,5) bu üç toplama arasında eşit olarak nasıl böldüğümüze dikkat edin:

func ComputeCountMeanSum(s beam.Scope, col beam.PCollection) (visitsPerHour, meanTimeSpent, revenues beam.PCollection) {
    s = s.Scope("ComputeCountMeanSum")
    // Create a Privacy Spec and convert col into a PrivatePCollection
    // Budget is shared by count, mean and sum.
    spec := pbeam.NewPrivacySpec(epsilon, /* delta */ 0)
    pCol := pbeam.MakePrivateFromStruct(s, col, spec, "VisitorID")

    // Create a PCollection of output partitions, i.e. restaurant's work hours
    // (from 9 am till 9pm (exclusive)).
    hours := beam.CreateList(s, [12]int{9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20})

    visitHours := pbeam.ParDo(s, extractVisitHourFn, pCol)
    visitsPerHour = pbeam.Count(s, visitHours, pbeam.CountParams{
        Epsilon:                  epsilon / 3,
        Delta:                    0,
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Visitors can visit the restaurant once within an hour
        MaxValue:                 1,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })

    hourToTimeSpent := pbeam.ParDo(s, extractVisitHourAndTimeSpentFn, pCol)
    meanTimeSpent = pbeam.MeanPerKey(s, hourToTimeSpent, pbeam.MeanParams{
        Epsilon:                      epsilon / 3,
        Delta:                        0,
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed:     1,
        // Visitors can visit the restaurant once within an hour
        MaxContributionsPerPartition: 1,
        // Minimum time spent per user (in mins)
        MinValue:                     0,
        // Maximum time spent per user (in mins)
        MaxValue:                     60,
        // Visitors only visit during work hours
        PublicPartitions:             hours,
    })

    hourToMoneySpent := pbeam.ParDo(s, extractVisitHourAndMoneySpentFn, pCol)
    revenues = pbeam.SumPerKey(s, hourToMoneySpent, pbeam.SumParams{
        Epsilon:                  epsilon / 3,
        Delta:                    0,
        // Visitors can visit the restaurant once (one hour) a day
        MaxPartitionsContributed: 1,
        // Minimum money spent per user (in euros)
        MinValue:                 0,
        // Maximum money spent per user (in euros)
        MaxValue:                 40,
        // Visitors only visit during work hours
        PublicPartitions:         hours,
    })

    return visitsPerHour, meanTimeSpent, revenues
}

9. (İsteğe bağlı) Diferansiyel gizlilik parametrelerini düzenleme

Bu codelab'de çok sayıda parametreden bahsedildi: epsilon, delta, maxPartitionsContributiond vb. Bu parametreleri genel olarak iki kategoriye ayırabiliriz: Gizlilik Parametreleri ve Yardımcı Program Parametreleri.

Gizlilik Parametreleri

Epsilon ve delta, diferansiyel gizlilik kullanarak sağladığımız gizliliği ölçen parametrelerdir. Daha ayrıntılı ifade etmek gerekirse epsilon ve delta, potansiyel bir saldırganın anonimleştirilmiş çıktıya bakarak temel verilerle ilgili ne kadar bilgi edindiğinin ölçüsüdür. Epsilon ve delta ne kadar yüksek olursa saldırganın temel veriler hakkında o kadar fazla bilgi edinir ve bu da gizlilik riski oluşturur.

Öte yandan, epsilon ve delta ne kadar düşük olursa anonim hale getirmek için çıkışa o kadar fazla gürültü eklemeniz ve bu bölümün anonimleştirilmiş çıktıda kalmasını sağlamak için her bölümde daha fazla benzersiz kullanıcınız olması gerekir. Bu durumda, hizmet ile gizlilik arasında bir denge vardır.

Işınlamada Gizlilik'te, PrivacySpec içinde toplam gizlilik bütçesini belirtirken anonimleştirilmiş çıkışınızda elde etmek istediğiniz gizlilik garantileriyle ilgili endişelenmeniz gerekir. Gizlilik garantilerinizin geçerli kalmasını istiyorsanız her toplama işlemi için ayrı bir PrivacySpec kullanarak veya ardışık düzeni birden çok kez çalıştırarak bu codelab'de bütçenizi fazla kullanmamanızla ilgili tavsiyelere uymanız gerekir.

Diferansiyel gizlilik ve gizlilik parametrelerinin ne anlama geldiği hakkında daha fazla bilgi için literatüre göz atabilirsiniz.

Yardımcı Program Parametreleri

Bunlar, gizlilik garantilerini etkilemeyen (Işık üzerinde gizliliğin kullanımı ile ilgili tavsiyeye uygun şekilde uyulduğu sürece) ancak doğruluğu ve sonuç olarak da çıktının faydasını etkileyen parametrelerdir. Bunlar her toplamanın Params yapısında sağlanır, ör. CountParams, SumParams vb. Bu parametreler, eklenen gürültüyü ölçeklendirmek için kullanılır.

Params içinde sağlanan ve tüm toplamalarda geçerli olan bir yardımcı program parametresi: MaxPartitionsContributed. Bölüm, Privacy On Beam toplama işlemi (ör. Count, SumPerKey) tarafından oluşturulan PCollection'ın anahtarına karşılık gelir. Bu nedenle MaxPartitionsContributed, kullanıcının çıkışa katkıda bulunabileceği farklı anahtar/değer sayısını sınırlar. Bir kullanıcı temel verilerde MaxPartitionsContributed taneden fazla anahtara katkıda bulunursa tam olarak MaxPartitionsContributed anahtara katkıda bulunabilmesi için bazı katkıları silinir.

MaxPartitionsContributed özelliğine benzer şekilde çoğu toplamada MaxContributionsPerPartition parametresi bulunur. Bunlar Params struct'larında sağlanır ve her toplama bunların için ayrı değerlere sahip olabilir. MaxPartitionsContributed yerine MaxContributionsPerPartition, bir kullanıcının her anahtar için katkısını sınırlar. Diğer bir deyişle, bir kullanıcı her anahtar için yalnızca MaxContributionsPerPartition değerleriyle katkıda bulunabilir.

Çıkışa eklenen gürültü, MaxPartitionsContributed ve MaxContributionsPerPartition oranında ölçeklendirilir. Bu nedenle, burada bir denge söz konusudur: MaxPartitionsContributed ve MaxContributionsPerPartition daha büyük olduğunda, daha fazla veri saklayabilirsiniz ancak sonuçta daha gürültülü bir sonuç elde edersiniz.

Bazı toplama işlemleri için MinValue ve MaxValue gerekir. Bunlar, her kullanıcının katkı sınırlarını belirler. MinValue değerinden daha düşük bir değere katkıda bulunan kullanıcılar için bu değer MinValue ile sabitlenir. Benzer şekilde, kullanıcı MaxValue değerinden daha büyük bir değere katkıda bulunursa bu değer MaxValue değerine ayarlanır. Bu, orijinal değerlerin daha fazlasını korumak için daha büyük sınırlar belirtmeniz gerektiği anlamına gelir. MaxPartitionsContributed ve MaxContributionsPerPartition işlemlerine benzer şekilde, gürültü, sınırların boyutlarına göre ölçeklendirilir. Dolayısıyla, daha büyük sınırlar, daha fazla veri sakladığınız anlamına gelir ancak sonuçta daha gürültülü bir sonuç elde edersiniz.

Bahseteceğimiz son parametre NoiseKind. Privacy On Beam'de iki farklı gürültü mekanizmasını destekliyoruz: GaussianNoise ve LaplaceNoise. Her ikisinin de avantajları ve dezavantajları vardır ancak Laplace dağıtımı düşük katkı sınırlarıyla daha iyi fayda sağlar. Bu nedenle Privacy On Beam varsayılan olarak gizlilik ayarını kullanır. Ancak, Gauss dağılım gürültüsü kullanmak istiyorsanız Params özelliğine bir pbeam.GaussianNoise{} değişkeni sağlayabilirsiniz.

10. Özet

Tebrikler! Beam'de gizlilik codelab'ini tamamladınız. Diferansiyel gizlilik ve Beam'de Gizlilik hakkında birçok şey öğrendiniz:

  • MakePrivateFromStruct numaralı telefonu arayarak PCollection kartınız PrivatePCollection içine dönüştürülüyor.
  • Diferansiyel gizli sayıları hesaplamak için Count kullanma.
  • Diferansiyel gizli araçları hesaplamak için MeanPerKey kullanma.
  • Diferansiyel özel toplamları hesaplamak için SumPerKey kullanma.
  • Tek bir ardışık düzende tek bir PrivacySpec ile birden fazla istatistik hesaplama.
  • (İsteğe bağlı) PrivacySpec ve toplama parametrelerini (CountParams, MeanParams, SumParams) özelleştirme.

Ancak Privacy on Beam ile yapabileceğiniz daha birçok toplama işlemi (ör.yüzdelik dilimler, farklı değerleri sayan) vardır. Bu sürümler hakkında daha fazla bilgiyi GitHub deposunda veya godoc'ta bulabilirsiniz.

Zamanınız varsa lütfen bir anketi doldurarak codelab hakkında geri bildirimde bulunun.