tag:blogger.com,1999:blog-45242764139576983422024-03-13T02:57:19.061+01:00Google Developers ItaliaLocal blog for Italian speaking developersGoogle Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.comBlogger721125tag:blogger.com,1999:blog-4524276413957698342.post-50719841015060242502020-02-17T08:00:00.000+01:002020-02-17T08:00:06.324+01:00Styling Android: temi e stiliPubblicato da <a class="dc dd bb bc bd be bf bg bh bi gp bl bm gq gr" href="https://medium.com/@crafty?source=post_page-----ebe05f917578----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Nick Butcher</a><br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="190" src="https://cdn-images-1.medium.com/max/1024/1*_oRkdiiwzxsiEKUW-KSRXg.png" width="640" /></div>
<figcaption style="text-align: center;">Illustrazione di <a href="https://twitter.com/VPoltrack">Virginia Poltrack</a></figcaption></figure><br />
Il <a href="https://developer.android.com/guide/topics/ui/look-and-feel/themes">sistema di styling Android</a> offre un modo efficace per specificare il design visivo della tua app, ma potrebbe essere facilmente usato in modo improprio. Il suo corretto utilizzo può semplificare la gestione di temi e stili, rendere meno "preoccupanti" gli aggiornamenti del marchio e semplificare il supporto delle modalità scure. Questo è il primo di una serie di articoli in cui <a href="https://medium.com/u/9303277cb6db">Chris Banes</a> e io inizieremo a smitizzare lo styling Android in modo che tu possa creare app eleganti senza strapparti i capelli.<br />
In questo primo articolo, analizzeremo gli elementi di base del sistema di styling: temi e stili.<br />
<h3>
Tema != Stile</h3>
Sia i temi che gli stili usano la stessa sintassi <style>, ma hanno scopi molto diversi. Puoi pensare a entrambi come ad archivi di chiavi-valori in cui le chiavi sono attributi e i valori sono risorse. Analizziamoli più in dettaglio.<br />
<h3>
Cosa c'è in uno stile?</h3>
Uno stile è una raccolta di valori degli attributi di visualizzazione. Puoi pensare a uno stile come a una Map<<strong>view</strong> attribute, resource>. Le chiavi sono tutti attributi di visualizzazione, ovvero attributi dichiarati da un widget e che è possibile impostare in un file di layout. Gli stili sono specifici di un singolo tipo di widget perché widget diversi supportano diversi set di attributi:<br />
<blockquote>
Gli stili sono una raccolta di attributi di visualizzazione; specifici per un singolo tipo di widget</blockquote>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/028aa3a4468271e89945e99e3804e3f9/href">https://medium.com/media/028aa3a4468271e89945e99e3804e3f9/href</a></iframe><br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<style name="Widget.Plaid.Button.InlineAction" parent="…">
<item name="android:gravity">center_horizontal</item>
<item name="android:textAppearance">@style/TextAppearance.CommentAuthor</item>
<item name="android:drawablePadding">@dimen/spacing_micro</item> </style></pre>
Come puoi vedere, ognuna delle chiavi nello stile rappresenta elementi che <em>potresti</em> impostare in un layout:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<Button …
android:gravity="center_horizontal"
android:textAppearance="@style/TextAppearance.CommentAuthor"
android:drawablePadding="@dimen/spacing_micro"/></pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/90e87f9d7da4a0859339f2131cda1129/href">https://medium.com/media/90e87f9d7da4a0859339f2131cda1129/href</a></iframe><br />
La loro estrazione in uno stile ne semplifica il riutilizzo in più visualizzazioni e la gestione.<br />
<h3>
Utilizzo</h3>
Gli stili vengono utilizzati dalle singole visualizzazioni da un layout:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<Button …
style="@style/Widget.Plaid.Button.InlineAction"/></pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/3230654de8923435a686c6e280dd8f5f/href">https://medium.com/media/3230654de8923435a686c6e280dd8f5f/href</a></iframe><br />
Le visualizzazioni possono applicare solo un singolo stile: confronta questa proprietà con altri sistemi di styling come CSS sul Web in cui i componenti possono impostare più classi CSS.<br />
<h3>
Ambito di applicazione</h3>
Uno stile applicato a una visualizzazione si applica <strong>solo</strong> a <em>quella</em> visualizzazione e a nessuno dei suoi elementi secondari. Ad esempio, se hai un ViewGroup con tre pulsanti, l'impostazione dello stile InlineAction sul ViewGroup non applicherà tale stile ai pulsanti. I valori forniti dallo stile sono combinati con quelli impostati direttamente nel layout (risolti usando l'<a href="https://medium.com/androiddevelopers/whats-your-text-s-appearance-f3a1729192d">ordine di precedenza dello styling</a>).<br />
<h3>
Che cos'è un tema?</h3>
Un tema è una raccolta di risorse denominate a cui stili, layout, ecc. possono fare riferimento in un secondo momento. Esse forniscono nomi semantici alle risorse Android in modo da potervi fare riferimento in seguito, ad esempio colorPrimary è un nome semantico per un determinato colore:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<style name="Theme.Plaid" parent="…">
<item name="colorPrimary">@color/teal_500</item>
<item name="colorSecondary">@color/pink_200</item>
<item name="android:windowBackground">@color/white</item>
</style></pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/abc4cc219fe0671c6bc37562163f065c/href">https://medium.com/media/abc4cc219fe0671c6bc37562163f065c/href</a></iframe><br />
Queste risorse denominate sono note come attributi del tema, quindi un tema è Map<<strong>theme</strong> attribute, resource>. Gli attributi del tema sono diversi dagli attributi della visualizzazione perché non sono proprietà specifiche di un singolo tipo di visualizzazione, ma puntatori <em>denominati semanticamente</em> a valori applicabili in modo più ampio in un'app. Un tema fornisce valori concreti per queste risorse denominate. Nell'esempio sopra l'attributo colorPrimary specifica che il colore primario per questo tema è verde acqua. Astraendo la risorsa con un tema, possiamo fornire diversi valori concreti (come colorPrimary=orange) in temi diversi.<br />
<blockquote>
I temi sono una raccolta di risorse denominate, utili in generale in un'app</blockquote>
Un tema è simile a un'interfaccia. La programmazione su un'interfaccia consente di separare il contratto pubblico dall'implementazione consentendoti di fornire implementazioni <em>diverse</em> . I temi hanno un ruolo simile; scrivendo i nostri layout e stili rispetto agli attributi del tema, possiamo usarli su temi diversi, fornendo diverse risorse concrete.<br />
Pseudo-codice approssimativamente equivalente:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">/* Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
interface ColorPalette {
@ColorInt val colorPrimary
@ColorInt val colorSecondary
}
class MyView(colors: ColorPalette) {
fab.backgroundTint = colors.colorPrimary
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/e7e8c1a0d64f51f54da720523855b683/href">https://medium.com/media/e7e8c1a0d64f51f54da720523855b683/href</a></iframe><br />
Ciò consente di variare il modo in cui viene visualizzato MyView, senza doverne creare delle varianti:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">/* Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 */
val lightPalette = object : ColorPalette { … }
val darkPalette = object : ColorPalette { … }
val view = MyView(if (isDarkTheme) darkPalette else lightPalette)</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/7d95e919f92eaa0738a65296c85f5060/href">https://medium.com/media/7d95e919f92eaa0738a65296c85f5060/href</a></iframe><br />
<h3>
Utilizzo</h3>
Puoi specificare un tema per i componenti che hanno (o sono) un Context, ad esempio Activity o Views/ViewGroups:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<!-- AndroidManifest.xml -->
<application …
android:theme="@style/Theme.Plaid">
<activity …
android:theme="@style/Theme.Plaid.About"/>
<!-- layout/foo.xml -->
<ConstraintLayout …
android:theme="@style/Theme.Plaid.Foo">
</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/42b3f1b63d5363397348485ecfd67bd1/href">https://medium.com/media/42b3f1b63d5363397348485ecfd67bd1/href</a></iframe><br />
Puoi anche impostare un tema nel codice includendo un Context esistente con un <a href="https://developer.android.com/reference/android/view/ContextThemeWrapper.html#ContextThemeWrapper(android.content.Context,%20int)">ContextThemeWrapper</a>, che poi potresti usare per eseguire l'<a href="https://developer.android.com/reference/android/view/LayoutInflater.html#from(android.content.Context)">inflation</a> di un layout ecc.<br />
Il potere dei temi deriva da come li usi; puoi creare widget più flessibili facendo riferimento agli attributi del tema. Temi diversi forniscono valori concreti in un secondo momento. Ad esempio, potresti voler impostare un colore di sfondo su una sezione della gerarchia di visualizzazione:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<ViewGroup …
android:background="?attr/colorSurface"></pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/a0173b29e7fc706443b029ce32b6a270/href">https://medium.com/media/a0173b29e7fc706443b029ce32b6a270/href</a></iframe><br />
Invece di impostare un colore statico (#ffffff o una risorsa @color), possiamo delegare al tema usando la sintassi ?attr/themeAttributeName. Questa sintassi significa: esegui una query al tema per il valore di questo attributo semantico. Questo livello di riferimento indiretto ci consente di fornire comportamenti diversi (ad esempio, impostando un colore di sfondo diverso nei temi chiari e scuri) senza dover creare layout o stili multipli che sono per lo più identici, ad eccezione di alcune variazioni di colore. Isola gli elementi che cambiano all'interno del tema.<br />
<blockquote>
Usa la sintassi ?attr/themeAttributeName per eseguire una query al tema per il valore di questo attributo semantico</blockquote>
<h3>
Ambito di applicazione</h3>
A un <a href="https://developer.android.com/reference/android/content/res/Resources.Theme.html">Theme</a> si accede come proprietà di un <a href="https://developer.android.com/reference/android/content/Context">Context</a> e può essere ottenuto da qualsiasi oggetto che sia o abbia un Context, ad esempio Activity, View o ViewGroup. Questi oggetti esistono in una struttura ad albero, in cui una Activity contiene ViewGroups che contengono Views, ecc. La specifica di un tema a qualsiasi livello di questo albero viene applicata anche ai nodi discendenti, ad es. l'impostazione di un tema su un ViewGroup si applica a tutte le visualizzazioni al suo interno (contrariamente agli stili, che si applicano solo a una singola visualizzazione).<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><!-- Copyright 2019 Google LLC.
SPDX-License-Identifier: Apache-2.0 -->
<ViewGroup …
android:theme="@style/Theme.App.SomeTheme">
<! - SomeTheme also applies to all child views. -->
</ViewGroup></pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/4e62ee24561fb31ee34cdec477b96c54/href">https://medium.com/media/4e62ee24561fb31ee34cdec477b96c54/href</a></iframe><br />
Ciò può essere estremamente utile, ad esempio se si desidera una sezione a tema scuro di uno schermo altrimenti chiaro. Maggiori informazioni su questo comportamento saranno fornite nel prossimo post (<em>presto disponibile!</em>).<br />
Questo comportamento si applica solo al momento dell'inflation del layout. Sebbene Context offra un metodo <a href="https://developer.android.com/reference/android/content/Context#setTheme(int)">setTheme</a> o Theme offra un metodo <a href="https://developer.android.com/reference/android/content/res/Resources.Theme?hl=en#applyStyle(int,%20boolean)">applyStyle</a>, questi devono essere chiamati <em>prima</em> dell'inflation. L'impostazione di un nuovo tema o l'applicazione di uno stile dopo l'inflation non aggiornerà le visualizzazioni esistenti.<br />
<h3>
Altre preoccupazioni</h3>
Comprendere le diverse responsabilità e l'interazione di stili e temi aiuta a mantenere più gestibili le risorse di styling.<br />
Ad esempio, supponi di avere un tema blu per la tua app, ma alcuni schermi Pro restituiscono un colore viola <strong>e</strong> vuoi fornire <a href="https://developer.android.com/guide/topics/ui/look-and-feel/darktheme">temi scuri</a> con colori ottimizzati. Se cercassi di raggiungere questo obiettivo utilizzando solo gli stili, dovresti creare 4 stili per le combinazioni di Pro/non-Pro e chiaro/scuro. Poiché gli stili sono specifici di un tipo di visualizzazione (Button, Switch ecc.), dovresti creare queste combinazioni per ciascun tipo di visualizzazione nell'app.<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="360" src="https://cdn-images-1.medium.com/max/1024/0*aKRwEx8Z0SCfN8hy" width="640" /></div>
<figcaption>Esplosione delle combinazioni di widget/stili senza l'uso dei temi</figcaption></figure><br />
Se invece usiamo stili <strong>e</strong> temi possiamo isolare le parti che cambiano in base al tema come attributi del tema e quindi dobbiamo solo definire un singolo stile per tipo di visualizzazione. Per l'esempio sopra potremmo definire 4 temi che forniscono ciascuno valori diversi per l'attributo del tema colorPrimary, a cui questi stili poi fanno riferimento e riflettono automaticamente il valore corretto dal tema.<br />
Questo approccio potrebbe sembrare più complicato in quanto è necessario considerare l'interazione di stili e temi, ma ha il vantaggio di isolare le parti che cambiano in base al tema. Quindi, se la tua app cambia da blu ad arancione, è sufficiente apportare questa modifica in un unico posto. Ciò consente inoltre di evitare la proliferazione di stili. Idealmente hai solo un piccolo numero di stili per tipo di visualizzazione. Se non approfitti dei temi, è facile che il tuo file styles.xml ti sfugga di mano ed esploda con diverse varianti di stili simili, con conseguenti problemi di gestione.<br />
Seguici nei prossimi articoli in cui esploreremo <em>l'utilizzo di</em> temi e stili (<em>presto disponibili!</em>)<br />
<!--<meta name="original_url" content="https://medium.com/androiddevelopers/android-styling-themes-vs-styles-ebe05f917578">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-73242630933505367102020-02-05T17:07:00.000+01:002020-02-05T17:07:05.000+01:00Modifica del tipo con typealiasPubblicato da <a class="dc dd bb bc bd be bf bg bh bi hb bl bm hc hd" href="https://medium.com/@florina.muntenescu?source=post_page-----4c03302fbe43----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Florina Muntenescu</a><br />
<br />
<img alt="" height="190" src="https://cdn-images-1.medium.com/max/1024/1*v3V2U8qG7bua3PGlA5t_KA.png" style="text-align: center;" width="640" /><br />
<br />
Vocabolario Kotlin: typealias<br />
Quando le definizioni del tipo distraggono dal significato del codice perché non sono leggibili o sono espressive o troppo lunghe, Kotlin ha la funzione giusta per te: <a href="https://kotlinlang.org/docs/reference/type-aliases.html">typealias</a>! Typealias consente di fornire nomi alternativi per i tipi di classe o funzione senza introdurre un nuovo tipo.<br />
<h3>
Utilizzo di typealias</h3>
Puoi usare i typealias per nominare un tipo di funzione:<br />
<pre>typealias TeardownLogic = () -> Unit
fun onCancel(teardown : TeardownLogic){ }</pre>
<pre>private typealias OnDoggoClick = (dog: Pet.GoodDoggo) -> Unit
val onClick: OnDoggoClick</pre>
Lo svantaggio è che il nome nasconde i parametri passati alla funzione, diminuendo la leggibilità:<br />
<pre>typealias TeardownLogic = () -> Unit //or
typealias TeardownLogic = (exception: Exception) -> Unit</pre>
<pre>fun onCancel(teardown : TeardownLogic){
// can’t easily see what information we have
// available in TeardownLogic
}</pre>
Typealias ti consente di abbreviare nomi generici lunghi:<br />
<pre>typealias Doggos = List<Pet.GoodDoggo></pre>
<pre>fun train(dogs: Doggos){ … }</pre>
Sebbene questo sia possibile, chiediti se davvero <em>dovresti</em> farlo. L'uso di un typealias rende davvero il tuo codice più significativo e leggibile?<br />
<blockquote>
Chiediti se l'uso di un typealias rende il tuo codice più comprensibile.</blockquote>
Se stai lavorando con un nome di classe lungo, puoi usare typealias per abbreviarlo:<br />
<pre>typealias AVD = AnimatedVectorDrawable</pre>
Ma per questo caso d'uso, una soluzione migliore sarebbe utilizzare un <a href="https://kotlinlang.org/docs/reference/packages.html#imports"><strong>import alias</strong></a>:<br />
<pre>import android.graphics.drawable.AnimatedVectorDrawable <strong>as</strong> AVD</pre>
Gli import alias diventano ancora più utili quando è necessario disambiguare classi con lo stesso nome, provenienti da pacchetti diversi:<br />
<pre>import io.plaidapp.R <strong>as</strong> appR</pre>
<pre>import io.plaidapp.<strong>about</strong>.R</pre>
I typealias sono definiti al di fuori delle classi, quindi assicurati di considerare la loro visibilità quando li usi.<br />
<h3>
Utilizzo di typealias in progetti multipiattaforma</h3>
Quando si lavora con <a href="https://kotlinlang.org/docs/reference/platform-specific-declarations.html">progetti multipiattaforma</a>, è possibile specificare interfacce nel codice comune che vengono quindi implementate nel codice della piattaforma. Per facilitare ciò, Kotlin fornisce un meccanismo di dichiarazioni attese ed effettive.<br />
Le interfacce nel codice comune sono le dichiarazioni attese, definite utilizzando la parola chiave attesa. L'implementazione nel codice della piattaforma viene definito utilizzando la parola chiave effettiva. Se l'implementazione esiste già in una delle piattaforme e ha tutti i metodi attesi con le stesse identiche firme, è possibile utilizzare typealias per mappare il nome della classe al nome atteso.<br />
<pre>expect annotation class Test</pre>
<pre>actual typealias Test = org.junit.Test</pre>
<h3>
Qualche dettaglio in più</h3>
I typealias non introducono nuovi tipi. Ad esempio, il codice decompilato per la funzione train utilizzerà solo un elenco:<br />
<pre>// Kotlin
typealias Doggos = List<Pet.GoodDoggo>
fun train(dogs: Doggos) { … }</pre>
<pre>// Decompiled Java code
public static final void train(@NotNull List dogs) { … }</pre>
<blockquote>
I typealias non introducono nuovi tipi.</blockquote>
I typealias non introducono nuovi tipi. Per questo motivo, non devi fare affidamento su di essi per i controlli del tipo di tempo di compilazione. Invece, dovresti considerare l'utilizzo di un tipo diverso o di una classe inline. Ad esempio, supponiamo di avere la seguente funzione:<br />
<pre>fun play(dogId: Long)</pre>
La creazione di un typealias su Long non ci aiuterà a prevenire errori quando proviamo a passare l'ID sbagliato:<br />
<pre>typealias DogId = Long</pre>
<pre>fun pet(dogId: DogId) { … }</pre>
<pre>fun usage() {
val cat = Cat(1L)
pet(cat.catId) // compiles
}</pre>
I typealias sono un modo per fornire un nome più breve o più significativo a un tipo esistente. Se quello che stai cercando è sicurezza aggiuntiva, probabilmente vorrai creare un nuovo tipo.<br />
<!--<meta name="original_url" content="https://medium.com/androiddevelopers/alter-type-with-typealias-4c03302fbe43">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-40585276165554956112020-01-31T08:00:00.000+01:002020-01-31T08:00:00.962+01:00Miglioramento del rilevamento fuori dalla distribuzione nei modelli di machine learning<span class="byline-author">Pubblicato da Jie Ren, Research Scientist, Google Research e Balaji Lakshminarayanan, Research Scientist, DeepMind</span> <br />
<br />
Il corretto deployment dei sistemi di machine learning richiede che il sistema sia in grado di distinguere tra dati anomali o significativamente diversi da quelli utilizzati nell'addestramento. Ciò è particolarmente importante per i classificatori di reti neurali profonde, che potrebbero classificare tali input <em>fuori distribuzione</em> (out-of-distribution, OOD) in classi di distribuzione con elevata sicurezza. Ciò è di fondamentale importanza quando queste previsioni vengono utilizzate per prendere decisioni nel mondo reale. <br />
<br />
Ad esempio, un'applicazione complessa dei modelli di machine learning per applicazioni del mondo reale è l'identificazione dei batteri basata su sequenze genomiche. Il rilevamento dei batteri è cruciale per la diagnosi e il trattamento di malattie infettive, come la sepsi, e per identificare i patogeni di origine alimentare. Ogni anno vengono scoperte nuove classi batteriche e, mentre un classificatore di reti neurali addestrato sulle classi conosciute raggiunge un'elevata precisione misurata attraverso la convalida incrociata, il deployment di un modello è complesso, poiché i dati del mondo reale sono in continua evoluzione e conterranno inevitabilmente genomi di classi non note (input OOD) e non presenti nei dati di addestramento. <br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLMch95oZ7CVXc2vpLAdJVpa9NcDLFqMPTZerBMreoSyYIYrP_d2vPkm3d8S1vypmE1IqLzQLJ_kezGwIJ4yVTUdT1IHqu90FmIMBokNimOYaPLv5cZCSVzAQg4kxYpea0qNeFyi0jW2eW/s1600/image15.gif" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="464" data-original-width="697" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLMch95oZ7CVXc2vpLAdJVpa9NcDLFqMPTZerBMreoSyYIYrP_d2vPkm3d8S1vypmE1IqLzQLJ_kezGwIJ4yVTUdT1IHqu90FmIMBokNimOYaPLv5cZCSVzAQg4kxYpea0qNeFyi0jW2eW/s400/image15.gif" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Nel corso degli anni vengono continuamente scoperte nuove classi batteriche. Un classificatore addestrato sulle classi conosciute ottiene un'elevata precisione per gli input di test appartenenti a classi note, ma può classificare erroneamente input da classi sconosciute (ovvero, fuori distribuzione) in classi note con sicurezza elevata.</td></tr>
</tbody></table>
In "<a href="https://arxiv.org/abs/1906.02845">Likelihood Ratios for Out-of-Distribution Detection</a>", presentato al <a href="https://nips.cc/Conferences/2019">NeurIPS 2019</a>, abbiamo proposto e <a href="https://git.io/JeP2s">rilasciato</a> un set di dati di riferimento realistico di sequenze genomiche per il rilevamento OOD ispirato alle sfide del mondo reale sopra descritte. Abbiamo testato metodi esistenti per il rilevamento OOD utilizzando modelli generativi su sequenze genomiche e abbiamo scoperto che i valori di <em><a href="https://en.wikipedia.org/wiki/Likelihood_function">verosimiglianza</a></em> , ovvero la probabilità del modello che un input provenga dalla distribuzione stimata utilizzando i dati di distribuzione, erano spesso in errore. Questo fenomeno è stato osservato anche in recenti lavori su modelli generativi profondi di immagini. Spieghiamo questo fenomeno attraverso l'effetto delle statistiche di sfondo e proponiamo una soluzione basata sul <em>rapporto di verosimiglianza</em> che migliora in modo significativo la precisione del rilevamento OOD.<br />
<br />
<b>Perché i modelli di densità generano errori nel rilevamento OOD?</b><br />
Per riprodurre il problema del mondo reale e valutare sistematicamente diversi metodi, abbiamo creato un nuovo set di dati batterici utilizzando dati provenienti dal <a href="https://www.ncbi.nlm.nih.gov/genome/browse#!/prokaryotes/">catalogo NCBI disponibile pubblicamente delle sequenze di genomi procariotici</a>. Per imitare i dati di sequenziamento, abbiamo frammentato i genomi in brevi sequenze di 250 coppie di basi, una lunghezza comunemente generata dall'attuale tecnologia di sequenziamento. Abbiamo quindi separato i dati in distribuzione e fuori distribuzione per data di scoperta, in modo tale che le classi batteriche scoperte prima di un tempo di cutoff fossero definite come in distribuzione e quelle scoperte successivamente come OOD. <br />
<br />
Abbiamo quindi addestrato un modello generativo profondo sulle sequenze genomiche in distribuzione ed esaminato le prestazioni del modello nel discriminare tra input interni ed esterni alla distribuzione, tracciando i relativi valori di verosimiglianza. L'istogramma della verosimiglianza per le sequenze OOD si sovrappone in gran parte a quello delle sequenze in distribuzione, indicando che il modello generativo non è stato in grado di distinguere tra le due popolazioni per il rilevamento OOD. Risultati simili sono stati mostrati in <a href="https://arxiv.org/abs/1810.01392">precedenti</a> <a href="https://arxiv.org/abs/1810.09136">lavori</a> per modelli generativi profondi, ad esempio, un modello <a href="https://arxiv.org/abs/1701.05517">PixelCNN++</a> addestrato su immagini dal set di dati <a href="https://github.com/zalandoresearch/fashion-mnist">Fashion-MNIST</a> (che consiste in immagini di abbigliamento e calzature) assegna una maggiore verosimiglianza alle immagini OOD dal set di dati <a href="http://yann.lecun.com/exdb/mnist/">MNIST</a> (che è costituito da immagini di cifre 0-9). <br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoJ6K5tTtkyKInY45As-79mFmA1S0BH-w8KegxhhdO3WbfMMddv06FVy8TCbO3EtghLqTBhAuB-GtDFenETTH8TBCglgTLh3nfeV-cyjXUziWj4wcUxOuUtGz5psVcn9tdjH_-FJJRVAz4/s1600/Histograms.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="444" data-original-width="1086" height="260" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoJ6K5tTtkyKInY45As-79mFmA1S0BH-w8KegxhhdO3WbfMMddv06FVy8TCbO3EtghLqTBhAuB-GtDFenETTH8TBCglgTLh3nfeV-cyjXUziWj4wcUxOuUtGz5psVcn9tdjH_-FJJRVAz4/s640/Histograms.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><b>A sinistra:</b> Istogramma dei valori di verosimiglianza per sequenze genomiche in distribuzione e fuori distribuzione (OOD). La verosimiglianza non riesce a separare le sequenze genomiche in distribuzione e OOD. <b>A destra:</b> Un grafico simile per un modello addestrato su Fashion-MNIST e valutato su MNIST. Il modello assegna valori di verosimiglianza più elevati per le immagini OOD (MNIST) rispetto alle immagini in distribuzione.</td></tr>
</tbody></table>
Quando abbiamo studiato questa modalità di errore, abbiamo osservato che la verosimiglianza può essere influenzata dalle statistiche di sfondo. Per comprendere il fenomeno in modo più intuitivo, supponiamo che un input sia composto da due componenti, (1) un componente <em>di sfondo</em> caratterizzato da statistiche di sfondo e (2) un componente <em>semantico,</em> caratterizzato da sequenze specifiche per i dati in distribuzione. Ad esempio, un'immagine MNIST può essere modellata come sfondo più semantica. Quando l'occhio umano interpreta l'immagine, può facilmente ignorare lo sfondo e concentrarsi principalmente sulle informazioni semantiche, ad esempio il segno "/" nell'immagine qui sotto. Ma la verosimiglianza viene calcolata per tutti i pixel di un'immagine, sia quelli semantici sia quelli di sfondo. Sebbene vogliamo usare solo la verosimiglianza semantica per il processo decisionale, la verosimiglianza raw può essere dominata dallo sfondo.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsjibfA8hIaLQ0IYlCL4rYTF-WVDHU9Rl7W05gk-yvefRNBnbEWaQCFxGfgF3O6zsfsu2uFINEIFChmh8OXUlvMybw1V5foDQIBwL6hZwRdbGyVNCwLresmAt2VpWtTnmOJvnJfcuaAc7k/s1600/Semantics.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="276" data-original-width="869" height="126" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsjibfA8hIaLQ0IYlCL4rYTF-WVDHU9Rl7W05gk-yvefRNBnbEWaQCFxGfgF3O6zsfsu2uFINEIFChmh8OXUlvMybw1V5foDQIBwL6hZwRdbGyVNCwLresmAt2VpWtTnmOJvnJfcuaAc7k/s400/Semantics.png" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><b>In alto a sinistra: </b>Immagini di esempio di Fashion-MNIST. <b>In basso a sinistra:</b> Immagini di esempio di MNIST. <b>A destra:</b> Componenti di sfondo e semantici in un'immagine MNIST.</td></tr>
</tbody></table>
<b>Rapporti di verosimiglianza per il rilevamento OOD</b><br />
Proponiamo un <em>metodo basato sul rapporto di verosimiglianza </em>che rimuove l'effetto dello sfondo e si concentra sulla semantica. Innanzitutto, addestriamo un modello di sfondo su input perturbati. Il metodo per perturbare l'input si ispira alle mutazioni genetiche e procede selezionando casualmente le posizioni nell'input e sostituendo il valore con un altro che abbia uguale probabilità. Per l'imaging, i valori vengono scelti casualmente tra i 256 possibili valori dei pixel e, per le sequenze di DNA, il valore viene selezionato tra i quattro possibili <a href="https://en.wikipedia.org/wiki/Nucleotide">nucleotidi</a> (A, T, C o G). La giusta quantità di perturbazione può "disturbare" la struttura semantica nei dati e acquisire solo lo sfondo. Quindi calcoliamo il rapporto di verosimiglianza tra il modello completo e il modello di sfondo, il componente di sfondo viene eliminato, in modo che rimanga solo la verosimiglianza semantica. Il rapporto di verosimiglianza è un <em>punteggio contrastivo dello sfondo,</em>ovvero cattura il significato della semantica rispetto allo sfondo. <br />
<br />
Per valutare qualitativamente la differenza tra la verosimiglianza e il rapporto di verosimiglianza, abbiamo tracciato i relativi valori per ciascun pixel nei set di dati Fashion-MNIST e MNIST, creando heatmap che hanno le stesse dimensioni delle immagini. Questo ci consente di visualizzare quali pixel contribuiscono maggiormente ai due termini, rispettivamente. Dalle heatmap log-verosimiglianza, vediamo che i pixel di sfondo contribuiscono molto di più alla verosimiglianza rispetto ai pixel semantici. Con il senno di poi, questo non è sorprendente, dal momento che i pixel di sfondo sono costituiti principalmente da una stringa di zeri, un modello appreso molto facilmente dal modello. Un confronto tra le heatmap MNIST e Fashion-MNIST dimostra perché MNIST restituisce valori di verosimiglianza più elevati: ha semplicemente molti più pixel di sfondo! Il rapporto di verosimiglianza si concentra invece maggiormente sui pixel semantici. <br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3NWN8-pvmtcKVMdxQEl6kT6gJcqn6dwJ7wQ9VY7adW3w1bqFxjkmmIVehrVrj6A-gzn63WpJPApdL-CAkkRBUwJ42HWwhlUwD070B5eOyBDCZyGTl8oPBYwSgeGVl9YbkAozPy9GJTwrj/s1600/LikelihoodCompare.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="342" data-original-width="1239" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg3NWN8-pvmtcKVMdxQEl6kT6gJcqn6dwJ7wQ9VY7adW3w1bqFxjkmmIVehrVrj6A-gzn63WpJPApdL-CAkkRBUwJ42HWwhlUwD070B5eOyBDCZyGTl8oPBYwSgeGVl9YbkAozPy9GJTwrj/s640/LikelihoodCompare.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><b>A sinistra:</b> Heatmap log-verosimiglianza per set di dati Fashion-MNIST e MNIST. <b>A destra:</b> Gli stessi esempi che mostrano le heatmap del rapporto di verosimiglianza. I pixel con valori più elevati sono di tonalità più chiare. La verosimiglianza è dominata dai pixel "di sfondo", mentre il rapporto di verosimiglianza si concentra sui pixel "semantici" ed è quindi migliore per il rilevamento OOD.</td></tr>
</tbody></table>
Il nostro metodo basato sul rapporto di verosimiglianza corregge l'effetto di sfondo e migliora significativamente il rilevamento OOD delle immagini MNIST da un <a href="https://en.wikipedia.org/wiki/Receiver_operating_characteristic#Area_under_the_curve">punteggio AUROC</a> di 0,089 a 0,994, in base a un modello PixelCNN++ addestrato per Fashion-MNIST. Quando viene applicato al set di dati di riferimento genomico, questo metodo ottiene prestazioni all'avanguardia su questo problema complesso, quando confrontato con altri 12 metodi di base. <br />
<br />
Per maggiori dettagli, consulta il nostro recente <a href="https://arxiv.org/abs/1906.02845">articolo</a> su NeurIPS 2019. Sebbene il nostro metodo basato sul rapporto di verosimiglianza raggiunga prestazioni all'avanguardia sul set di dati genomico, non ha ancora un'accuratezza sufficientemente elevata da raggiungere gli standard che consentano il deployment del modello in applicazioni reali. Incoraggiamo i ricercatori a contribuire con le loro soluzioni a questo importante problema e a migliorare l'attuale stato dell'arte. Il set di dati è disponibile sul nostro <a href="https://git.io/JeP2s">repository GitHub</a>. <br />
<br />
<b><em>Ringraziamenti</em></b><br />
<em>Il lavoro qui descritto è stato scritto da Jie Ren, Peter J. Liu, Emily Fertig, Jasper Snoek, Ryan Poplin, Mark A. DePristo, Joshua V. Dillon, Balaji Lakshminarayanan, attraverso una collaborazione con diversi team di Google AI e DeepMind. Siamo grati per tutte le discussioni e i feedback su questo lavoro ricevuti dai revisori di NeurIPS 2019 e dai nostri colleghi di Google e DeepMind: Alexander A. Alemi, Andreea Gane, Brian Lee, D. Sculley, Eric Jang, Jacob Burnim, Katherine Lee, Matthew D. Hoffman, Noah Fiedel, Rif A. Saurous, Suman Ravuri, Thomas Colthurst, Yaniv Ovadia, insieme ai team Google Brain e TensorFlow. </em><!--<meta name="original_url" content="http://ai.googleblog.com/2019/12/improving-out-of-distribution-detection.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-17631096672075280432020-01-29T08:00:00.000+01:002020-01-29T08:00:09.258+01:00Creare un Web più privato: un percorso per rendere obsoleti i cookie di terze parti<span style="font-family: inherit;">Ad agosto abbiamo </span><a href="https://www.blog.google/products/chrome/building-a-more-private-web/" style="font-family: inherit;" target="_blank">annunciato</a><span style="font-family: inherit;"> una nuova iniziativa (nota come Privacy Sandbox) volta a sviluppare un set di standard aperti finalizzati a incrementare in modo significativo la privacy sul Web. Il nostro obiettivo per questa iniziativa open source è rendere il Web più privato e sicuro per gli utenti, senza tuttavia smettere di supportare i publisher. Oggi, desideriamo aggiornarti sui nostri piani e chiedere il tuo aiuto per aumentare la privacy dell'esplorazione del Web.</span><br />
<span style="font-family: inherit;"><br />Dopo il dialogo iniziale con la community del Web, siamo fiduciosi che, grazie a iterazione e feedback costanti, i meccanismi di tutela della privacy e attuazione di standard aperti come Privacy Sandbox saranno in grado di sostenere un Web supportato dalle inserzioni che sia sicuro, in modo tale da rendere i cookie di terze parti obsoleti. Una volta che questi approcci saranno stati adattati alle esigenze di utenti, publisher e inserzionisti e che avremo sviluppato gli strumenti per mitigare eventuali espedienti, elimineremo gradualmente il supporto per i cookie di terze parti in Chrome. E siamo intenzionati a raggiungere questo obiettivo entro due anni. Tuttavia non possiamo farcela da soli, ecco perché abbiamo bisogno che l'intero ecosistema Web prenda parte alla realizzazione di queste proposte. Abbiamo in programma di iniziare le prime versioni di valutazione entro la fine di quest'anno, a partire dalla misurazione delle conversioni per poi proseguire con la personalizzazione.<br /> <br />Gli utenti chiedono maggiore privacy, trasparenza, possibilità di scelta e controllo sul modo in cui i loro dati vengono utilizzati, ed è chiaro che l'ecosistema Web debba evolversi per poter soddisfare queste richieste crescenti. Alcuni browser hanno reagito a queste preoccupazioni bloccando i cookie di terze parti, ma noi crediamo che un simile approccio implichi conseguenze inattese che potrebbero avere un impatto negativo sia sugli utenti che sull'ecosistema Web. Riteniamo infatti che approcci drastici ai cookie, minando il modello di business di molti siti web supportati dalle inserzioni, finiscano per incoraggiare il ricorso a tecniche invasive come l'uso di impronte per sostituire i cookie, le quali rischiano di compromettere la privacy e il controllo degli utenti. La nostra convinzione è che tutti insieme, come community, possiamo e dobbiamo fare meglio.<br /><br />Fortunatamente, abbiamo ricevuto feedback positivi in forum come W3C in merito al fatto che i meccanismi alla base di Privacy Sandbox rappresentino casi d'uso fondamentali e vadano nella giusta direzione. Questi feedback, e le relative proposte avanzate da altri partecipanti agli standard, rafforzano la nostra convinzione che le soluzioni nate in questo spazio possano funzionare. Inoltre, la nostra esperienza con la community degli standard nella creazione di alternative e nell'<a href="https://www.blog.google/products/chrome/saying-goodbye-flash-chrome/" target="_blank">eliminazione graduale del supporto a Flash </a>e <a href="https://blog.chromium.org/2014/11/the-final-countdown-for-npapi.html" target="_blank">NPAPI</a> è la dimostrazione che insieme possiamo affrontare e superare sfide difficili.<br /><br />Intanto, continueremo a lavorare per rendere le tecnologie web attuali più sicure e private. Come abbiamo già annunciato, a partire da febbraio Chrome limiterà il monitoraggio intersito non sicuro trattando i cookie che non includono un'etichetta SameSite solo come prima parte; inoltre, richiederà che i cookie etichettati per l'uso di terze parti siano accessibili tramite HTTPS. Questo renderà i cookie di terze parti più sicuri e fornirà gli utenti controlli più precisi sui cookie del browser. Parallelamente, stiamo sviluppando tecniche volte a rilevare e mitigare sistemi di tracciamento nascosto e altri espedienti grazie a nuove misure anti-rilevamento dell'impronta per scoraggiare questo genere di tecniche ingannevoli e invasive, che puntiamo a lanciare entro quest'anno.<br /> <br />Stiamo lavorando attivamente nell'ecosistema perché browser, publisher, sviluppatori e inserzionisti abbiano l'opportunità di sperimentare questi nuovi meccanismi, testarne l'efficacia in diverse situazioni e creare implementazioni di supporto come la selezione e la misurazione delle inserzioni, la prevenzione denial of service (DoS), misure anti-spam/frode e un'autenticazione federata.<br /> <br />Ci stiamo impegnando per dare vita a un Web più sicuro e sostenibile, insieme, e per riuscirci abbiamo bisogno del tuo impegno costante. Ti invitiamo a fornirci un <a href="https://github.com/w3c/web-advertising/blob/master/README.md" target="_blank">feedback</a> sulle proposte presentate dalla <a href="https://www.w3.org/community/web-adv/" target="_blank">community di standard per il Web</a> attraverso GitHub, assicurandoti che soddisfino le tue esigenze. In caso contrario, presenta un issue tramite GitHub o contatta via <a href="https://lists.w3.org/Archives/Public/public-web-adv/" target="_blank">email</a> il gruppo W3C. Se la tua attività si svolge sul Web, assicurati che i tuoi fornitori di tecnologia prendano parte a questo processo e condividi il tuo feedback con i gruppi commerciali che rappresentano i tuoi interessi.<br /><br />Noi continueremo a tenervi aggiornati sui risultati del nostro lavoro volto ad accrescere la privacy dell'esplorazione del Web.<br /><br />Pubblicato da Justin Schuh - Director, Chrome Engineering</span><br />
<span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <span class="post-author"><br /></span> <!--<meta name="original_url" content="http://blog.chromium.org/2020/01/building-more-private-web-path-towards.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-77615513330001511062020-01-27T08:00:00.000+01:002020-01-27T08:00:18.117+01:00Fairness Indicators: infrastruttura scalabile per sistemi ML equi<span class="byline-author">Pubblicato da Catherina Xu e Tulsee Doshi, Product Managers, Google Research</span> <br />
<br />
Mentre l'industria e il mondo accademico continuano a esplorare i vantaggi dell'utilizzo del machine learning (ML) per realizzare prodotti migliori e affrontare problemi importanti, gli algoritmi e i set di dati su cui vengono addestrati possono anche riflettere o rafforzare bias ingiusti. Ad esempio, contrassegnare costantemente commenti testuali non tossici di alcuni gruppi come "spam" o "ad alta tossicità" in un sistema di moderazione porta all'esclusione di tali gruppi dalla conversazione. <br />
<br />
Nel 2018, abbiamo condiviso il modo in cui Google utilizza l'AI per creare prodotti più utili, <a href="https://www.blog.google/technology/ai/ai-principles/">evidenziando i principi dell'AI</a> che guideranno il nostro lavoro in futuro. Il secondo principio, "Evitare di creare o rafforzare bias ingiusti", delinea il nostro impegno a ridurre i bias ingiusti e minimizzare il loro impatto sulle persone.<br />
<br />
Nell'ambito di questo impegno, al <a href="https://conferences.oreilly.com/tensorflow/tf-ca/schedule/2019-10-28">TensorFlow World</a> abbiamo recentemente rilasciato una versione beta di <a href="https://github.com/tensorflow/fairness-indicators">Fairness Indicators</a>, una suite di strumenti che consente il calcolo e la visualizzazione regolari delle metriche di equità per la classificazione binaria e multi-classe, aiutando i team a fare un primo passo verso l'identificazione di impatti non equi. I Fairness Indicators possono essere utilizzati per generare metriche per i report sulla trasparenza, come quelli utilizzati per le <a href="https://modelcards.withgoogle.com/about?utm_source=googleaiblog&utm_medium=blog&utm_campaign=fairness-indicators-cs&utm_term=&utm_content=blog-mc">schede modello</a>, per aiutare gli sviluppatori a prendere decisioni migliori su come distribuire i modelli in modo responsabile. Poiché le preoccupazioni e le valutazioni sull'equità differiscono caso per caso, in questa versione abbiamo incluso anche un <a href="https://developers.google.com/machine-learning/practica/fairness-indicators?utm_source=aiblog&utm_medium=blog&utm_campaign=fi-practicum&utm_term=&utm_content=blog-body">case study interattivo</a> con il <a href="https://jigsaw.google.com/">set di dati</a> <a href="https://www.kaggle.com/c/jigsaw-unintended-bias-in-toxicity-classification">Unintended Bias in Toxicity di Jigsaw</a> per illustrare come i Fairness Indicators possano essere utilizzati per rilevare e correggere i bias in un modello di machine learning (ML) in produzione, a seconda del contesto in cui è distribuito. I Fairness Indicators sono <a href="https://github.com/tensorflow/fairness-indicators">ora disponibili in versione beta</a>, per consentirti di provarli nei tuoi casi d'uso. <br />
<br />
<h3>
<b>Che cos'è l'equità ML?</b></h3>
Il bias può manifestarsi in qualsiasi parte di una tipica pipeline di machine learning, da un set di dati non rappresentativo a <a href="https://en.wikipedia.org/wiki/Feature_learning">rappresentazioni</a> di modelli addestrati fino al modo in cui i risultati vengono presentati all'utente. Gli errori che derivano da questo bias possono avere un impatto sproporzionato su alcuni utenti più che su altri.<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAVI5CVBIg8GwIpc6eqHUVyJMEuDbcexTOLHwhGvxk83kEC9b6nfKwYfmYZP2DoSl_KnzDkFGA-6qA_H_JSs0VwJEnJOy8hN4c4JkOEPprgGngfr-o0ftNokbYBz0MRLYesJxpxiNS_oeW/s1600/image2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="893" data-original-width="1600" height="356" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiAVI5CVBIg8GwIpc6eqHUVyJMEuDbcexTOLHwhGvxk83kEC9b6nfKwYfmYZP2DoSl_KnzDkFGA-6qA_H_JSs0VwJEnJOy8hN4c4JkOEPprgGngfr-o0ftNokbYBz0MRLYesJxpxiNS_oeW/s640/image2.png" width="640" /></a></div>
<br />
Per rilevare questo impatto diseguale, la valutazione su singole sezioni o gruppi di utenti è fondamentale, in quanto le metriche complessive possono oscurare le scarse prestazioni di determinati gruppi. Questi gruppi possono includere, a titolo esemplificativo, quelli definiti da caratteristiche sensibili come razza, etnia, genere, nazionalità, reddito, orientamento sessuale, abilità e credo religioso. Tuttavia, è anche importante tenere presente che l'equità non può essere raggiunta solo attraverso metriche e misurazioni; prestazioni elevate, anche tra le varie sezioni, non dimostrano necessariamente che un sistema sia equo. Piuttosto, la valutazione deve essere vista come uno dei primi modi, soprattutto per i modelli di classificazione, per identificare eventuali lacune nelle prestazioni. <br />
<br />
<h3>
<b>La suite di strumenti Fairness Indicators</b></h3>
La suite di strumenti Fairness Indicators consente il calcolo e la visualizzazione delle metriche di equità comunemente identificate per i modelli di classificazione, come il tasso di falsi positivi e il tasso di falsi negativi, semplificando il confronto delle prestazioni tra le varie sezioni o con una sezione di riferimento. Lo strumento calcola gli <a href="https://en.wikipedia.org/wiki/Confidence_interval">intervalli di confidenza</a>, che possono far emergere disparità statisticamente significative,<em> </em>ed esegue una valutazione su più soglie. Nella UI è possibile attivare/disattivare la sezione di riferimento e studiare le prestazioni di varie altre metriche. L'utente può anche aggiungere le proprie metriche per la visualizzazione, specifiche del proprio caso d'uso.<br />
<br />
Inoltre, i Fairness Indicators sono integrati con il <a href="https://pair-code.github.io/what-if-tool/">What-If Tool</a> (WIT): facendo clic su una barra nel grafico dei Fairness Indicators, questi punti di dati specifici verranno caricati nel widget WIT per ulteriori ispezioni, confronti e analisi controfattuali. Ciò è particolarmente utile per set di dati di grandi dimensioni, in cui i Fairness Indicators possono essere utilizzati per identificare sezioni problematiche prima che il WIT venga utilizzato per un'analisi più approfondita. <br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz18jFNW0wz9rC3i5IuZy-YWr8nOls0b93pv1m6Qv0WcMjWVGUSJZItn7VM43biqDi0UNUlm1YfIJ6OKjgMDMnG64h2AB3bya2WdTb8J1JdGVG_SWgoY4mih7R0kjT31S0jbRohGpLqqXv/s1600/image1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="547" data-original-width="925" height="378" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhz18jFNW0wz9rC3i5IuZy-YWr8nOls0b93pv1m6Qv0WcMjWVGUSJZItn7VM43biqDi0UNUlm1YfIJ6OKjgMDMnG64h2AB3bya2WdTb8J1JdGVG_SWgoY4mih7R0kjT31S0jbRohGpLqqXv/s640/image1.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Utilizzo dei Fairness Indicators per visualizzare le metriche per la valutazione dell'equità.</td></tr>
</tbody></table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnyXq7q2iGQVg9mpMF5vM0VfOXnv6vDHfH2b6d_NIPxGoxsoutcLhBxRAbGQ23-BxiIcgog_mBCIxtOebGyOLwfplxweLw_NUzq_pAFPYTNrD52VsSIj-Ny0xUqtMW5adp4hlBIQ8iX3cD/s1600/image3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="787" data-original-width="1600" height="314" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjnyXq7q2iGQVg9mpMF5vM0VfOXnv6vDHfH2b6d_NIPxGoxsoutcLhBxRAbGQ23-BxiIcgog_mBCIxtOebGyOLwfplxweLw_NUzq_pAFPYTNrD52VsSIj-Ny0xUqtMW5adp4hlBIQ8iX3cD/s640/image3.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Facendo clic su una sezione nei Fairness Indicators, verranno caricati tutti i punti dati in quella sezione all'interno del widget What-If Tool. In questo caso, vengono mostrati tutti i punti dati con l'etichetta "femmina".</td></tr>
</tbody></table>
Il lancio della beta di Fairness Indicators include quanto segue: <br />
<ul>
<li><b><a href="https://pypi.org/project/fairness-indicators/">Pacchetto pip</a>:</b> include <a href="https://www.tensorflow.org/tfx/tutorials/model_analysis/tfma_basic">Tensorflow Model Analysis</a> (TFMA), Fairness Indicators, <a href="https://www.tensorflow.org/tfx/data_validation/get_started">Tensorflow Data Validation</a> (TFDV), What-If Tool e Colab di esempio: <br />
<ul>
<li><a href="https://github.com/tensorflow/fairness-indicators/blob/master/fairness_indicators/examples/Fairness_Indicators_Example_Colab.ipynb">Fairness Indicators Example Colab</a>: un'introduzione all'utilizzo dei Fairness Indicators <br />
</li>
<li><a href="https://github.com/tensorflow/fairness-indicators/blob/master/fairness_indicators/examples/Fairness_Indicators_TensorBoard_Plugin_Example_Colab.ipynb">Fairness Indicators for TensorBoard</a>: un esempio di utilizzo del plug-in <a href="https://www.tensorflow.org/tensorboard">TensorBoard</a><br />
</li>
<li><a href="https://github.com/tensorflow/fairness-indicators/blob/master/fairness_indicators/examples/Fairness_Indicators_on_TF_Hub_Text_Embeddings.ipynb">Fairness Indicators with TFHub Embeddings</a>: un Colab che indaga gli effetti di diversi embedding sulle metriche di equità a valle<br />
</li>
<li><a href="https://github.com/tensorflow/fairness-indicators/blob/master/fairness_indicators/examples/Facessd_Fairness_Indicators_Example_Colab.ipynb">Fairness Indicators with Cloud Vision API's Face Detection Model</a>: un Colab che mostra come i Fairness Indicators possono essere utilizzati per generare risultati di valutazione per le <a href="https://modelcards.withgoogle.com/face-detection">schede del modello</a><br />
</li>
</ul>
</li>
<li><b><a href="https://github.com/tensorflow/fairness-indicators">Repository GitHub</a>: </b>Codice sorgente<br />
</li>
<li><b><a href="https://github.com/tensorflow/fairness-indicators/blob/master/fairness_indicators/documentation/guidance.md">Linee guida per l'uso</a>: </b>l'equità è altamente contestuale ed è importante riflettere attentamente su ciascun caso d'uso e sulle potenziali implicazioni per gli utenti. Questo documento fornisce linee guida per la selezione di gruppi e metriche ed evidenzia le best practice per la valutazione.<br />
</li>
<li><b><a href="https://developers.google.com/machine-learning/practica/fairness-indicators">Case study</a>: </b>case study interattivo sull'uso dei Fairness Indicators, che mostra come il team Conversation AI di Jigsaw rileva il bias in un modello di classificazione utilizzando il <a href="https://www.kaggle.com/c/jigsaw-toxic-comment-classification-challenge">set di dati Toxic Comment Classification</a>.<br />
</li>
</ul>
<h3>
<b>Come utilizzare oggi i Fairness Indicators nei modelli</b></h3>
I Fairness Indicators si basano su TensorFlow Model Analysis, un componente di <a href="https://www.tensorflow.org/tfx">TensorFlow Extended</a> (TFX) che può essere utilizzato per studiare e visualizzare le prestazioni del modello. Sulla base del flusso di lavoro ML specifico, i Fairness Indicators possono essere incorporati in un sistema in uno dei seguenti modi: <br />
Se si utilizzano modelli e strumenti TensorFlow, come TFX: <br />
<ul>
<li>Accedere ai Fairness Indicators come parte del componente <a href="https://www.tensorflow.org/tfx/guide/evaluator">Evaluator</a> in TFX<br />
</li>
<li>Accedere ai Fairness Indicators in <a href="https://github.com/tensorflow/tensorboard/blob/master/docs/fairness-indicators.md">TensorBoard</a> durante la valutazione di altre metriche in tempo reale<br />
</li>
</ul>
Se non si utilizzano gli strumenti TensorFlow esistenti: <br />
<ul>
<li>Scaricare il pacchetto pip Fairness Indicators e utilizzare Tensorflow Model Analysis come <a href="https://www.tensorflow.org/tfx/guide/fairness_indicators">strumento autonomo</a><br />
</li>
</ul>
Per i modelli non TensorFlow: <br />
<ul>
<li>Utilizzare <a href="https://www.tensorflow.org/tfx/guide/fairness_indicators#model_agnostic_evaluation">Model Agnostic TFMA</a> per calcolare i Fairness Indicators in base all'output di qualsiasi modello<br />
</li>
</ul>
<h3>
<b>Case study Fairness Indicators </b></h3>
Abbiamo creato un <a href="https://developers.google.com/machine-learning/practica/fairness-indicators?utm_source=aiblog&utm_medium=aiblog&utm_campaign=fi-practicum&utm_content=fi-practicum">case study</a> e un <a href="https://www.youtube.com/watch?v=pHT-ImFXPQo">video introduttivo</a> che illustra come i Fairness Indicators possano essere utilizzati con una combinazione di strumenti per rilevare e mitigare i bias in un modello addestrato sul <a href="https://www.kaggle.com/c/jigsaw-unintended-bias-in-toxicity-classification">set di dati Unintended Bias in Toxicity</a> di Jigsaw. Il set di dati è stato sviluppato da Conversation AI, un team di Jigsaw che lavora per addestrare modelli ML per proteggere le voci nelle conversazioni. I modelli sono addestrati per prevedere se i commenti testuali siano probabilmente abusivi in una varietà di dimensioni tra cui tossicità, insulto ed esplicitazione sessuale. <br />
<br />
Il caso d'uso principale per modelli come questi è la moderazione dei contenuti. Se un modello penalizza determinati tipi di messaggi in modo sistematico (ad esempio, contrassegna spesso i commenti come tossici quando non lo sono, portando a un alto tasso di falsi positivi), tali voci verranno messe a tacere. Nel case study, abbiamo studiato il tasso di falsi positivi su sottogruppi suddivisi per parole chiave di identità di genere presenti nel set di dati, utilizzando una combinazione di strumenti (Fairness Indicators, TFDV e WIT) per rilevare, diagnosticare e adottare misure per correggere il problema sottostante. <br />
<br />
<h3>
<b>E ora?</b></h3>
I Fairness Indicators sono solo il primo passo. Abbiamo in programma di espanderci <em>verticalmente</em> abilitando più metriche supportate, come metriche che consentono di valutare classificatori senza soglie e <em>orizzontalmente</em> creando librerie di riparazione che utilizzano metodi, come <a href="https://en.wikipedia.org/wiki/Active_learning_(machine_learning)">apprendimento attivo</a> e <a href="https://arxiv.org/pdf/1901.04562.pdf">min-diff</a>. Poiché riteniamo che sia importante imparare attraverso esempi concreti, speriamo di fondare il nostro lavoro su altri casi di studio che verranno rilasciati nei prossimi mesi, man mano che saranno disponibili più funzionalità. <br />
<br />
Per iniziare, consulta il <a href="https://github.com/tensorflow/fairness-indicators">repository GitHub di Fairness Indicators</a>. Per ulteriori informazioni su come pensare alla valutazione dell'equità nel contesto del tuo caso d'uso, consulta <a href="https://github.com/tensorflow/fairness-indicators/blob/master/fairness_indicators/documentation/guidance.md">questo link</a>. <br />
<br />
Ci piacerebbe collaborare con te per capire dove i Fairness Indicators sono più utili e dove sarebbero preziose funzionalità aggiuntive. Contattaci all'indirizzo <a href="mailto:tfx@tensorflow.org">tfx@tensorflow.org</a> per inviarci un feedback sulla tua esperienza! <br />
<br />
<h3>
<b>Ringraziamenti</b></h3>
<em>Il team principale alla base di questo lavoro comprende Christina Greer, Manasi Joshi, Huanming Fang, Shivam Jindal, Karan Shukla, Osman Aka, Sanders Kleinfeld, Alicia Chang, Alex Hanna e Dan Nanas. Vorremmo anche ringraziare James Wexler, Mahima Pushkarna, Meg Mitchell e Ben Hutchinson per il loro contributo al progetto. </em> <!--<meta name="original_url" content="http://ai.googleblog.com/2019/12/fairness-indicators-scalable.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-88123210172545338862020-01-24T08:00:00.000+01:002020-01-24T08:00:03.002+01:00Sospensione sulle viste - Esempio<div style="text-align: left;">
Pubblicato da <a class="dc dd bb bc bd be bf bg bh bi hh bl bm hi hj" href="https://medium.com/@chrisbanes?source=post_page-----260ce3dc9100----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Chris Banes</a></div>
<h4>
Un esempio elaborato dall'app <a href="https://tivi.app/">Tivi</a></h4>
<div style="text-align: center;">
<img alt="" height="190" src="https://cdn-images-1.medium.com/max/1024/1*UNsWjHpaQaS_yNNQ3ZyHpw.png" width="640" /><span style="font-size: x-small;"><span style="text-align: center;">Illustrazione di </span><a href="https://medium.com/@VPoltrack" style="text-align: center;">Virginia Poltrack</a></span></div>
<div style="text-align: center;">
<br /></div>
Questo post sul blog è il secondo dei due post che mostrano come le coroutine consentano di scrivere complesse operazioni UI asincrone in modo molto più semplice. Il primo post descrive la teoria, mentre questo mostra come è possibile risolvere un problema specifico.<br />
Se vuoi consultare il primo post, puoi trovarlo qui:<br />
<a href="https://medium.com/androiddevelopers/suspending-over-views-19de9ebd7020">Sospensione sulle viste</a><br />
Prendiamo ciò che abbiamo appreso nel post precedente e applichiamolo a un caso di utilizzo di app nel mondo reale.<br />
<h3>
Il problema</h3>
Qui abbiamo la UI dei dettagli dei programmi TV dell'app di esempio <a href="https://tivi.app/">Tivi</a>. Oltre alle informazioni sui programmi, elenca le stagioni e gli episodi. Quando l'utente fa clic su uno degli episodi, i dettagli dell'episodio vengono visualizzati utilizzando un'animazione che espande l'elemento selezionato:<br />
<br />
<br />
<br />
<figure><img alt="" height="640" src="https://cdn-images-1.medium.com/max/1024/0*EsI9PnKr_ilUWvco" width="640" /><figcaption style="text-align: center;">Espansione episodio (velocità 20%)</figcaption></figure><br />
L'app utilizza la libreria <a href="https://github.com/saket/InboxRecyclerView"><strong>InboxRecyclerView</strong></a> per gestire l'animazione di espansione precedente:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">fun onEpisodeItemClicked(view: View, episode: Episode) {
// Tell InboxRecyclerView to expand the episode item.
// We pass it the ID of the item to expand
recyclerView.expandItem(episode.id)
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/af84b36b2b481525fbab682b6a6cffa7/href">https://medium.com/media/af84b36b2b481525fbab682b6a6cffa7/href</a></iframe><br />
<br />
InboxRecyclerView funziona fornendo l'ID elemento della vista da espandere. Quindi trova la vista corrispondente dagli elementi di RecyclerView ed esegue l'animazione su di essa.<br />
Ora diamo un'occhiata al problema che stiamo cercando di risolvere. Nella parte superiore della stessa UI è presente un elemento diverso, che mostra all'utente il prossimo episodio da guardare. Utilizza lo stesso tipo di vista dell'elemento del singolo episodio mostrato sopra, ma ha un ID elemento diverso.<br />
Vista la mia pigrizia, per facilitare lo sviluppo ho usato lo stesso onEpisodeItemClicked() per questo elemento. Sfortunatamente questo ha portato a un'interruzione dell'animazione al momento del clic.<br />
<br />
<br />
<br />
<figure><img alt="" height="640" src="https://cdn-images-1.medium.com/max/1024/1*i_oNV5lx9HgxCuYPFspoNA.gif" width="640" /><figcaption style="text-align: center;">Espansione elemento errata (velocità 20%)</figcaption></figure><br />
Invece di espandere l'elemento cliccato, la libreria espande un elemento apparentemente casuale in alto. Questo non è l'effetto desiderato ed è causato da alcuni problemi sottostanti:<br />
<ol>
<li>L'ID che utilizziamo nel listener di clic viene preso direttamente dalla classe Episode. Questo ID è associato all'elemento dell'episodio singolo nell'elenco delle stagioni.</li>
<li>L'elemento dell'episodio potrebbe non essere collegato a RecyclerView. Affinché la vista esista in RecyclerView, l'utente dovrebbe aver allargato la stagione <em>e</em> scorso in modo tale che l'elemento sia nell'area visibile.</li>
</ol>
A causa di questi problemi, la libreria espande il primo elemento.<br />
<h3>
Soluzione ideale</h3>
Quindi qual è il comportamento previsto? Idealmente avremmo qualcosa del genere (rallentato:<br />
<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="640" src="https://cdn-images-1.medium.com/max/1024/0*Fq3dnDwt9_m-0k0S" width="640" /></div>
<figcaption style="text-align: center;">Il risultato ideale (velocità 20%)</figcaption></figure><br />
In pseudo-codice potrebbe apparire così:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">fun onNextEpisodeToWatchItemClick(view: View, nextEpisodeToWatch: Episode) {
// Tell the ViewModel to include the season’s episodes in the
// RecyclerView data set. This will trigger a database fetch, and update
// the view state
viewModel.expandSeason(nextEpisodeToWatch.seasonId)
// Scroll the RecyclerView so that the episode is displayed
recyclerView.scrollToItemId(nextEpisodeToWatch.id)
// Expand the item like before
recyclerView.expandItem(nextEpisodeToWatch.id)
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/60b6e10f9199b5822d8fb4cc8a7b82c4/href">https://medium.com/media/60b6e10f9199b5822d8fb4cc8a7b82c4/href</a></iframe><br />
In realtà, però, dovrebbe assomigliare di più a questo:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">fun onNextEpisodeToWatchItemClick(view: View, nextEpisodeToWatch: Episode) {
// Tell the ViewModel to include the season’s episodes in the
// RecyclerView data set. This will trigger a database fetch
viewModel.expandSeason(nextEpisodeToWatch.seasonId)
// TODO wait for new state dispatch from the ViewModel
// TODO wait for RecyclerView adapter to diff new data set
// TODO wait for RecyclerView to layout any new items
// Scroll the RecyclerView so that the episode is displayed
recyclerView.scrollToItemId(nextEpisodeToWatch.id)
// TODO wait for RecyclerView scroller to finish
// Expand the item like before
recyclerView.expandItem(nextEpisodeToWatch.id)
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/885fcd85828b64090e2e4bce88b8aff3/href">https://medium.com/media/885fcd85828b64090e2e4bce88b8aff3/href</a></iframe><br />
Come puoi vedere, bisogna aspettare un bel po' per l'esecuzione di attività asincrone! ⏳<br />
Lo pseudo-codice qui non sembra troppo complesso, ma quando inizi a implementarlo ti ritrovi presto impantanato in un mare di callback. Ecco un tentativo di scrivere una soluzione scheletro usando callback concatenati:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">fun expandEpisodeItem(itemId: Long) {
recyclerView.expandItem(itemId)
}
fun scrollToEpisodeItem(position: Int) {
recyclerView.smoothScrollToPosition(position)
// Add a scroll listener, and wait for the RV to be become idle
recyclerView.addOnScrollListener(object : OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
expandEpisodeItem(episode.id)
}
}
})
}
fun waitForEpisodeItemInAdapter() {
// We need to wait for the adapter to contain the item id
val position = adapter.findItemIdPosition(itemId)
if (position != RecyclerView.NO_POSITION) {
// The item ID is in the adapter, now we can scroll to it
scrollToEpisodeItem(itemId))
} else {
// Otherwise we wait for new items to be added to the adapter and try again
adapter.registerAdapterDataObserver(object : AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
waitForEpisodeItemInAdapter()
}
})
}
}
// And tell the ViewModel to give us the expanded season data set
viewModel.expandSeason(nextEpisodeToWatch.seasonId)
// Now need to wait for the new data
waitForEpisodeItemInAdapter()</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/85db9ec4cd02698ffdcaa9bf78690c4b/href">https://medium.com/media/85db9ec4cd02698ffdcaa9bf78690c4b/href</a></iframe><br />
Questo codice non è particolarmente ben scritto e probabilmente non funziona, ma lo scopo è mostrare come le callback possano rendere la programmazione della UI davvero complessa. In genere, questo codice presenta alcuni problemi:<br />
<h4>
Strettamente accoppiate</h4>
Dal momento che dobbiamo scrivere la nostra transizione usando i callback, ogni "animazione" deve essere consapevole di cosa chiamare successivamente: Il callback n. 1 chiama l'animazione 2, il callback n. 2 chiama l'animazione n. 3 e così via. Queste animazioni non hanno alcuna relazione l'una con l'altra, ma siamo stati costretti ad accoppiarle insieme.<br />
<h4>
Difficile da mantenere/aggiornare</h4>
Due mesi dopo aver scritto questo codice, il tuo motion designer ti chiede di aggiungere una transizione di dissolvenza nel mezzo. Dovrai tracciare la transizione, passando attraverso ogni callback per trovare il callback corretto in cui attivare la nuova animazione. Quindi dovrai provarla...<br />
<h4>
Test</h4>
Testare le animazioni è sempre difficile, ma barcamenarsi in questo mare di callback lo rende ancora più complesso. Il test deve riguardare tutti i diversi tipi di animazione e tutti i callback per verificare che tutto funzioni correttamente. In questo articolo non analizziamo i test in dettaglio, ma è un'attività che le coroutine rendono molto più facile.<br />
<h3>
Coroutine in soccorso </h3>
Nel primo post abbiamo imparato come includere un'API di callback in una funzione di sospensione. Usiamo questa conoscenza per trasformare il nostro terribile codice di callback in questo:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">viewLifecycleOwner.lifecycleScope.launch {
// await until the adapter contains the episode item ID
adapter.awaitItemIdExists(episode.id)
// Find the position of the season item
val seasonItemPosition = adapter.findItemIdPosition(episode.seasonId)
// Scroll the RecyclerView so that the season item is at the
// top of the viewport
recyclerView.smoothScrollToPosition(seasonItemPosition)
// ...and await that scroll to finish
recyclerView.awaitScrollEnd()
// Finally, expand the episode item to show the episode details
recyclerView.expandItem(episode.id)
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/7e3f991858ad1add78db73f84aa6969b/href">https://medium.com/media/7e3f991858ad1add78db73f84aa6969b/href</a></iframe><br />
Non è decisamente più leggibile?<br />
Le nuove funzioni di sospensione dell'attesa nascondono tutta la complessità, determinando un elenco sequenziale di chiamate di funzione. Entriamo più nei dettagli...<br />
<h3>
MotionLayout.awaitTransitionComplete()</h3>
Al momento non ci sono estensioni <a href="https://developer.android.com/reference/android/support/constraint/motion/MotionLayout">MotionLayout</a> ktx disponibili e, inoltre, <a href="https://developer.android.com/reference/android/support/constraint/motion/MotionLayout">MotionLayout</a> attualmente non ha la possibilità di aggiungere più di un listener alla volta (<a href="https://issuetracker.google.com/issues/144714753">richiesta di funzionalità</a>). Ciò significa che l'implementazione della funzione awaitTransitionComplete() è un po' più complicata rispetto ad alcune delle altre funzioni.<br />
Usiamo una sottoclasse di <a href="https://developer.android.com/reference/android/support/constraint/motion/MotionLayout">MotionLayout</a> che aggiunge il supporto per più listener: <a href="https://gist.github.com/chrisbanes/a7371683c224464bf6bda5a25491aee0">MultiListenerMotionLayout</a>.<br />
La nostra funzione waititTransitionComplete() viene quindi definita come:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">/**
* Wait for the transition to complete so that the given [transitionId] is fully displayed.
*
* @param transitionId The transition set to await the completion of
* @param timeout Timeout for the transition to take place. Defaults to 5 seconds.
*/
suspend fun MultiListenerMotionLayout.awaitTransitionComplete(transitionId: Int, timeout: Long = 5000L) {
// If we're already at the specified state, return now
if (currentState == transitionId) return
var listener: MotionLayout.TransitionListener? = null
try {
withTimeout(timeout) {
suspendCancellableCoroutine<Unit> { continuation ->
val l = object : TransitionAdapter() {
override fun onTransitionCompleted(motionLayout: MotionLayout, currentId: Int) {
if (currentId == transitionId) {
removeTransitionListener(this)
continuation.resume(Unit)
}
}
}
// If the coroutine is cancelled, remove the listener
continuation.invokeOnCancellation {
removeTransitionListener(l)
}
// And finally add the listener
addTransitionListener(l)
listener = l
}
}
} catch (tex: TimeoutCancellationException) {
// Transition didn't happen in time. Remove our listener and throw a cancellation
// exception to let the coroutine know
listener?.let(::removeTransitionListener)
throw CancellationException("Transition to state with id: $transitionId did not" +
" complete in timeout.", tex)
}
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/8413e58b122855719b10c06ed460e3ee/href">https://medium.com/media/8413e58b122855719b10c06ed460e3ee/href</a></iframe><br />
<h3>
Adapter.awaitItemIdExists()</h3>
Questa funzione è probabilmente piuttosto di nicchia, ma è molto utile. Nell'esempio dei programmi TV precedenti, in realtà gestisce alcuni stati asincroni diversi:<br />
<pre>// Make sure that the season is expanded, with the episode attached
viewModel.expandSeason(nextEpisodeToWatch.seasonId)</pre>
<pre><strong>// 1. Wait for new data dispatch
// 2. Wait for RecyclerView adapter to diff new data set</strong></pre>
<pre>// Scroll the RecyclerView so that the episode is displayed
recyclerView.scrollToItemId(nextEpisodeToWatch.id)</pre>
La funzione viene implementata usando <a href="https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.AdapterDataObserver.html">AdapterDataObserver</a> di RecyclerView, che viene chiamato ogni volta che cambia il set di dati dell'adattatore:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">/**
* Await an item in the data set with the given [itemId], and return its adapter position.
*/
suspend fun <VH : RecyclerView.ViewHolder> RecyclerView.Adapter<VH>.awaitItemIdExists(itemId: Long): Int {
val currentPos = findItemIdPosition(itemId)
// If the item is already in the data set, return the position now
if (currentPos >= 0) return currentPos
// Otherwise we register a data set observer and wait for the item ID to be added
return suspendCancellableCoroutine { continuation ->
val observer = object : RecyclerView.AdapterDataObserver() {
override fun onItemRangeInserted(positionStart: Int, itemCount: Int) {
(positionStart until positionStart + itemCount).forEach { position ->
// Iterate through the new items and check if any have our itemId
if (getItemId(position) == itemId) {
// Remove this observer so we don't leak the coroutine
unregisterAdapterDataObserver(this)
// And resume the coroutine
continuation.resume(position)
}
}
}
}
// If the coroutine is cancelled, remove the observer
continuation.invokeOnCancellation {
unregisterAdapterDataObserver(observer)
}
// And finally register the observer
registerAdapterDataObserver(observer)
}
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/b74c8f48a72d1189f1498c1a99a2e947/href">https://medium.com/media/b74c8f48a72d1189f1498c1a99a2e947/href</a></iframe><br />
<h3>
RecyclerView.awaitScrollEnd()</h3>
L'ultima funzione da evidenziare è <a href="https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.html">RecyclerView</a>.awaitScrollEnd(), che attende che lo scorrimento sia terminato:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">suspend fun RecyclerView.awaitScrollEnd() {
// If a smooth scroll has just been started, it won't actually start until the next
// animation frame, so we'll await that first
awaitAnimationFrame()
// Now we can check if we're actually idle. If so, return now
if (scrollState == RecyclerView.SCROLL_STATE_IDLE) return
suspendCancellableCoroutine<Unit> { continuation ->
continuation.invokeOnCancellation {
// If the coroutine is cancelled, remove the scroll listener
recyclerView.removeOnScrollListener(this)
// We could also stop the scroll here if desired
}
addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
// Make sure we remove the listener so we don't leak the
// coroutine continuation
recyclerView.removeOnScrollListener(this)
// Finally, resume the coroutine
continuation.resume(Unit)
}
}
})
}
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/05b0092654a7053786eaa8108152559a/href">https://medium.com/media/05b0092654a7053786eaa8108152559a/href</a></iframe><br />
Spero che ora questo codice risulti abbastanza comprensibile. Il problema con questa funzione è la necessità di utilizzare awaitAnimationFrame() prima di eseguire il controllo fail-fast. Come menzionato nei commenti, ciò è dovuto al fatto che uno <a href="https://developer.android.com/reference/androidx/recyclerview/widget/RecyclerView.SmoothScroller.html">SmoothScroller</a> inizia al successivo frame di animazione, quindi bisogna attendere che ciò accada prima di controllare lo stato di scorrimento.<br />
awaitAnimationFrame() è un wrapper su <a href="https://developer.android.com/reference/android/view/View.html#postOnAnimation(java.lang.Runnable)">postOnAnimation ()</a>, che ci consente di attendere il successivo step temporale dell'animazione, che in genere si verifica al rendering della visualizzazione successiva. È implementato come nell'esempio doOnNextLayout() dal primo post:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">suspend fun View.awaitAnimationFrame() = suspendCancellableCoroutine<Unit> { continuation ->
val runnable = Runnable {
continuation.resume(Unit)
}
// If the coroutine is cancelled, remove the callback
continuation.invokeOnCancellation { removeCallbacks(runnable) }
// And finally post the runnable
postOnAnimation(runnable)
}</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/5d35f3c5471318a1d26f6c6b8fca5ef5/href">https://medium.com/media/5d35f3c5471318a1d26f6c6b8fca5ef5/href</a></iframe><br />
<h3>
Risultato finale</h3>
Alla fine, la sequenza delle operazioni è simile alla seguente:<br />
<br />
<br />
<br />
<figure><img alt="" height="640" src="https://cdn-images-1.medium.com/max/1024/0*91F1ef4ZWLOzSRfp" width="640" /><figcaption style="text-align: center;">Soluzione, suddivisa in passaggi (velocità 20%)</figcaption></figure><br />
<h3>
Rompere le catene dei callback ⛓️</h3>
Passando alle coroutine, il nostro codice è in grado di eliminare lunghissime catene di callback, che sono difficili da mantenere e testare.<br />
La ricetta per racchiudere un'API callback/listener/observer in una funzione di sospensione è sostanzialmente la stessa per tutte le API. Spero che le funzioni mostrate in questo post siano ora di facile comprensione. Quindi non ti resta che liberare il codice della tua UI dalle catene dei callback!<br />
<!--<meta name="original_url" content="https://medium.com/androiddevelopers/suspending-over-views-example-260ce3dc9100">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-68296571380580855582020-01-22T16:50:00.000+01:002020-01-22T16:52:56.255+01:00Aggiornamenti da Coral: Mendel Linux 4.0 e molto altro!<em>Pubblicato da <a href="http://twitter.com/chemendonca">Carlos Mendonça</a> (Product Manager), <a href="http://coral.ai/">Coral Team</a></em>
<img alt="Illustrazione di Coral Dev Board posta accanto alle foglie autunnali" border="0" data-original-height="1043" data-original-width="1600" height="417" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8mtKVP_yluH9km2lSiNV2Q8W0iDe0ThdFyEJpeqiZ0ifCr0v1ew3kvmnfG10U4vF58rJqKP9DjZpEJQH44S8y4Ig3J29AlIWy6Xlrk68-F_5bF5fdDqqKLn-Hz2rk1voe1AzSc6r9dew/s640/Coral+Fall+Updates+-+illustration+v3.png" width="640" />
<br />
Abbiamo già annunciato che Coral è uscito dalla beta, passando a una versione più ampia e globale. Stavolta annunciamo la nuova versione di <a href="https://coral.ai/software/#mendel-linux">Mendel Linux</a> (4.0 release Day) per Coral Dev Board e SoM, oltre a numerosi altri interessanti aggiornamenti.
<br />
Abbiamo apportato aggiornamenti significativi per migliorare le prestazioni e la stabilità. Mendel Linux 4.0 release Day si basa su Debian 10 Buster e include pipeline GStreamer aggiornate e supporto per Python 3.7, OpenCV e OpenCL. Anche il kernel Linux è stato aggiornato alla versione 4.14 e U-Boot alla versione 2017.03.3.
<br />
Abbiamo anche reso possibile l'uso della GPU di Dev Board per convertire YUV in dati di pixel RGB fino a 130 fotogrammi al secondo con una risoluzione di 1080p, ovvero da uno a due ordini di grandezza più veloce rispetto a Mendel Linux 3.0 release Chef. Queste modifiche consentono di eseguire inferenze con fonti che producono YUV come telecamere e decoder video hardware.
<br />
Per aggiornare Dev Board o SoM, segui la nostra guida per <a href="https://coral.ai/docs/dev-board/reflash/#flash-a-new-system-image">ripristinare una nuova immagine di sistema da unità USB</a>.
<br />
<h3>
MediaPipe su Coral</h3>
<a href="https://mediapipe.dev/">MediaPipe</a> è un framework open source multipiattaforma per la creazione di pipeline di percezione del machine learning multimodali in grado di elaborare dati di streaming come video e audio. Ad esempio, puoi utilizzare MediaPipe per eseguire modelli di machine learning on-device ed elaborare video da una telecamera per <a href="https://mediapipe.page.link/handgoogleaiblog">rilevare, tracciare e visualizzare i punti di riferimento della mano</a> in tempo reale.
<br />
Sviluppatori e ricercatori possono prototipare i loro casi d'uso in tempo reale sulla percezione a partire dalla creazione del grafico MediaPipe sul desktop. Quindi, possono convertire ed eseguire il deployment rapidamente del grafico su Coral Dev Board, dove il modello quantizzato TensorFlow Lite sarà accelerato dalla Edge TPU.
<br />
Come parte di questa prima release, MediaPipe mette a disposizione nuovi esempi sperimentali per il rilevamento di oggetti e volti, con il supporto per Coral Dev Board e SoM. Il codice sorgente e le istruzioni per la compilazione e l'esecuzione di ciascun esempio sono <a href="https://github.com/google/mediapipe/tree/master/mediapipe/examples/coral">disponibili su GitHub</a> e sul <a href="https://mediapipe.readthedocs.io/en/latest/examples.html#google-coral-machine-learning-acceleration-with-google-edgetpu">sito della documentazione di MediaPipe</a>.
<br />
<h3>
Nuovo tutorial sul progetto Teachable Sorter</h3>
<div style="text-align: center;">
<img alt="Nuovo tutorial sul progetto Teachable Sorter" border="0" data-original-height="490" data-original-width="872" height="359" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5xjfxXatLoyuyXwWPhMwiltCneBYoP07vFKnWnObhaP1eC0H4SgX7RdWktiyY-g-ZGKny7NMSyT4g5lRlw0OLE4jcArVgXJs4cQLngKbXp55oKRbo-4yI7v2SrVp5EGVJqyRcy832nhM/s640/teachable+sorter.gif" width="640" />
</div>
È disponibile un nuovo tutorial per <a href="https://coral.ai/projects/teachable-sorter/">Teachable Sorter</a>. Teachable Sorter è una selezionatrice fisica che combina la capacità del Coral USB Accelerator di eseguire un'inferenza di latenza molto bassa con un modello ML che può essere addestrato per riconoscere e ordinare rapidamente diversi oggetti mentre cadono nel vuoto. Sfrutta la nuova <a href="https://teachablemachine.withgoogle.com/">Teachable Machine 2.0</a> di Google, un'applicazione Web che consente a chiunque di addestrare rapidamente un modello in modo divertente e pratico.
<br />
Il tutorial spiega come costruire la selezionatrice a caduta libera, che separa i marshmallow dai cereali e che può essere addestrata usando la Teachable Machine.
<br />
<h3>
Coral è ora su TensorFlow Hub</h3>
All'inizio di questo mese, il team TensorFlow ha annunciato una nuova versione di <a href="https://tfhub.dev/">TensorFlow Hub</a>, un archivio centrale di modelli pre-addestrati. Con questo aggiornamento, l'interfaccia è stata migliorata con una pagina di destinazione e un'esperienza di ricerca nuove. I modelli Coral pre-addestrati compilati per la Edge TPU continuano a essere disponibili sul <a href="https://coral.ai/models/">nostro sito Coral</a>, ma alcuni sono ora disponibili anche dal TensorFlow Hub. Sul sito è possibile trovare modelli con un'interfaccia Overlay, che consente di testare le prestazioni del modello in base a un set personalizzato di immagini direttamente dal browser. Scopri l'esperienza per <a href="https://tfhub.dev/tensorflow/mobilenet_v1_1.0_224_quantized/1">MobileNet v1</a> e <a href="https://tfhub.dev/tensorflow/mobilenet_v2_1.0_224_quantized/1">MobileNet v2</a>.
<br />
Siamo entusiasti di condividere tutto ciò che Coral ha da offrire mentre continuiamo a lavorare per far evolvere la nostra piattaforma. Per un elenco di distributori, integratori di sistemi e partner in tutto il mondo, visita la <a href="https://coral.ai/partnerships">nuova pagina dedicata alle partnership di Coral</a>. Speriamo che utilizzerai le nuove funzionalità offerte su <a href="https://coral.ai/">Coral.ai</a> come risorsa e ti incoraggiamo a continuare a inviarci feedback all'indirizzo <a href="mailto:coral-support@google.com">coral-support@google.com</a>.
<br />
<!--<meta name="original_url" content="http://developers.googleblog.com/2019/11/updates-from-coral-mendel-linux-4.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-17745120924588244672020-01-21T08:00:00.000+01:002020-01-21T08:00:02.248+01:00Now in Android: Pubblicato da <a class="dc dd bb bc bd be bf bg bh bi gf bl bm gg gh" href="https://medium.com/@chethaase?source=post_page-----23ae439e70f1----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Chet Haase</a><img alt="" height="190" src="https://cdn-images-1.medium.com/max/1024/0*-R_zo2spK2Vqxtzj" style="text-align: center;" width="640" /><br />
<br />
<figure>
<figcaption style="text-align: center;">Illustrazione di <a href="https://twitter.com/VPoltrack">Virginia Poltrack</a></figcaption></figure><br />
Benvenuto su Now in Android, la tua guida sulle novità nel mondo dello sviluppo di Android.<br />
Ciao a tutti, bentornati dalle vacanze! È passato un po' di tempo dall'ultimo Now in Android, perché molti di noi erano più impegnati a tavola che concentrati sui byte del software. Ma recentemente sono successe alcune cose che vale la pena analizzare mentre i nostri cervelli sfogliano collettivamente il nuovo anno e tutti proviamo a rispondere alla stessa domanda: Che cosa stavamo facendo l'ultima volta che abbiamo chiuso i nostri laptop?<br />
<h3>
Nuova documentazione: Room e KTX</h3>
<h4>
Una marea di documentazione</h4>
Le relazioni sono una delle cose più difficili da gestire nella vita. Non sarebbe bello se ci fosse una documentazione chiara per farle funzionare?<br />
Il tech writer Alex Cook ha migliorato la situazione fornendo una nuova <a href="https://developer.android.com/training/data-storage/room/relationships">guida alle relazioni tra entità in Room</a>. @Florina ha trattato parte di questo materiale in <a href="https://medium.com/androiddevelopers/database-relations-with-room-544ab95e4542">un recente articolo</a>, ma ora tutte le informazioni sulle relazioni sono concentrate in un'unica posizione sul nostro sito principale dedicato alla documentazione.<br />
Relazioni: Non possiamo risolverle, ma possiamo renderle più facili da capire... per Room.<br />
Un'altra guida su Room fornita da Alex di recente è <a href="https://developer.android.com/training/data-storage/room/prepopulate">Prepopola il tuo database Room</a>. Nella <a href="https://developer.android.com/jetpack/androidx/releases/room#2.2.0">versione 2.2</a>, rilasciata lo scorso ottobre, Room forniva la possibilità di pre-inizializzare il database dell'app all'avvio da un file sul dispositivo locale. <a href="https://developer.android.com/training/data-storage/room/prepopulate">Questa nuova guida</a> ti dice come usare questa funzione.<br />
<h4>
Estensioni KTX</h4>
<a href="https://developer.android.com/kotlin/ktx">Android KTX</a> fornisce funzioni di estensione di Kotlin per classi esistenti, per semplificare l'utilizzo delle API Android. Pensa a loro come a un modo per migliorare le API nel nostro mondo di compatibilità con le versioni precedenti, in cui non possiamo modificare le API principali perché altrimenti le app non funzionerebbero più. Oltre ad API più eleganti e più semplici, sfruttano le funzionalità chiave di Kotlin come lambda, parametri nominati e predefiniti, coroutine e (sì!) funzioni di estensione per migliorare ulteriormente le API e integrarsi facilmente nel flusso di sviluppo di Kotlin.<br />
Ma il problema è: come scoprire quali funzioni di estensione esistono?<br />
In precedenza, per trovare documenti di riferimento per una particolare funzione di estensione, dovevi sapere cosa stavi cercando per selezionare il riferimento al pacchetto appropriato che ospitava i documenti sull'estensione. È come avere le chiavi della tua auto, ma non sapere dove l'hai parcheggiata o in quale città. Una volta arrivato sul posto va tutto bene, ma trovarla può essere... difficile.<br />
<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" src="https://cdn-images-1.medium.com/max/218/1*coOIMG0hbvjpOOm2BgyWgA.png" /></div>
<figcaption style="text-align: center;">Tutti i pacchetti con estensioni KTX in un semplice sommario</figcaption></figure><br />
<a href="https://twitter.com/jbax_google">Joshua Baxter</a> del team della documentazione ha fornito una soluzione: la pagina <a href="https://developer.android.com/kotlin/ktx/extensions-list">Elenco delle estensioni di KTX</a>. Qui troverai tutte le estensioni offerte da KTX, indicate facilmente per sezioni di contenuto sul lato destro del documento. Il documento contiene collegamenti alla dichiarazione effettiva della funzione di estensione (che può contenere ulteriori informazioni, ad esempio <a href="https://developer.android.com/reference/kotlin/androidx/benchmark/junit4/package-summary#(androidx.benchmark.junit4.BenchmarkRule).measureRepeated(kotlin.Function1)">esempi di codice</a>), nonché i collegamenti alla classe che viene estesa.<br />
Ora puoi sfogliare o trovare più facilmente una determinata estensione o il set di estensioni per una determinata classe. Questo documento include anche informazioni su <a href="https://developer.android.com/kotlin/ktx#other">altre librerie KTX</a> oltre ad AndroidX. <a href="https://developer.android.com/kotlin/ktx#firebase">Firebase</a> e <a href="https://developer.android.com/kotlin/ktx#play-core">Play Core</a> hanno funzioni di estensione KTX che vale la pena provare.<br />
<h3>
Librerie AndroidX</h3>
A metà dicembre sono state rilasciate alcune nuove versioni delle librerie AndroidX. Innanzitutto, c'erano alcune librerie esistenti che sono diventate stabili:<br />
<ul>
<li><a href="https://developer.android.com/jetpack/androidx/releases/biometric#1.0.1">Biometric 1.0.1</a>: questa libreria consente di utilizzare l'autenticazione biometrica, senza preoccuparsi delle modifiche apportate alle API della piattaforma di autenticazione sottostante nelle ultime versioni. Quest'ultima versione è incentrata per lo più sulle correzioni di bug.</li>
<li><a href="https://developer.android.com/jetpack/androidx/releases/browser#1.2.0">Browser 1.2.0</a>: la 1.2.0 introduce Dark Theme e Trusted Web Activities.</li>
<li><a href="https://developer.android.com/jetpack/androidx/releases/enterprise#1.0.0">Enterprise 1.0.0</a>: le API di feedback enterprise ora hanno raggiunto la stabilità con la loro prima versione.</li>
<li><a href="https://developer.android.com/jetpack/androidx/releases/paging#2.1.1">Paging 2.1.1</a>: la libreria di paging semplifica il caricamento graduale dei dati con RecyclerView. Questa versione presenta miglioramenti di funzionalità minori rispetto alla precedente.</li>
<li><a href="https://developer.android.com/jetpack/androidx/releases/room#2.2.3">Room 2.2.3</a>: la libreria Room crea una potente astrazione e API su SQLite. La versione 2.2.3 è una versione bugfix minore.</li>
</ul>
Alcune librerie sono state inoltre rilasciate in <a href="https://developer.android.com/jetpack/androidx/versions/alpha-channel">versione alpha</a>. In particolare, non lasciarti sfuggire una nuova libreria che è stata rilasciata nella sua prima versione alpha (quindi forse non è ancora pronta per la prima serata, ma è interessante da provare se ti interessa questa funzionalità):<br />
<ul>
<li><a href="https://developer.android.com/jetpack/androidx/releases/concurrent#1.1.0-alpha01">Concurrent-Futures 1.1.0-alpha01</a>: questa libreria è utile se sei alla ricerca di funzionalità future come offerte <a href="https://github.com/google/guava">Guava</a>, senza voler inserire tutta la libreria.</li>
</ul>
<h3>
Articolo: osservazione dei database di Room con Flow</h3>
<br />
<br />
<br />
<figure style="text-align: center;"><img alt="" height="213" src="https://cdn-images-1.medium.com/max/1024/0*60kU8w-Z3Hh4jQPm.gif" width="640" /></figure><br />
Nella <a href="https://developer.android.com/jetpack/androidx/releases/room#2.2.0">versione 2.2.0</a>, Room ha aggiunto la possibilità di utilizzare l'API Flow di Kotlin per poter osservare le modifiche nel database. <a href="https://medium.com/u/d5885adb1ddf">Florina Muntenescu</a> ha pubblicato <a href="https://medium.com/androiddevelopers/room-flow-273acffe5b57">Room Flow</a>, mostrando come eseguire questa azione.<br />
<h3>
Codelab: Coroutine avanzate con Kotlin Flow e LiveData</h3>
<a href="https://medium.com/u/52873e9e8e">Tiem Song</a> e <a href="https://medium.com/u/83518fe480be">Sean McQuillan</a> hanno creato <a href="https://goo.gle/advanced-coroutines-codelab">questo codelab</a> per il workshop <em>Kotlin in Android</em> alla <a href="https://kotlinconf.com/">KotlinConf</a>, per mostrare come utilizzare LiveData con Coroutine e la nuova API Flow di Kotlin. Segui il <a href="https://goo.gle/advanced-coroutines-codelab">codelab</a> per un'esperienza completa o tuffati direttamente nel <a href="https://github.com/googlecodelabs/kotlin-coroutines/tree/master/advanced-coroutines-codelab">codice</a> se preferisci.<br />
<h3>
Video della conferenza</h3>
Oggi uno degli aspetti più belli delle conferenze, rispetto a qualche anno fa, è che le sessioni sono generalmente registrate e pubblicate per poter essere messe a disposizione di tutti.<br />
Trovo ancora utile andare a una conferenza di persona per vivere quella sensazione di immergersi nei contenuti per uno o più giorni, ma anche perché posso parlare con tutti i partecipanti. Ma non è fisicamente possibile partecipare a tutte le conferenze a cui mi piacerebbe andare, né è possibile guardare tutti i contenuti live di un evento con molteplici interventi concomitanti. È fantastico avere disponibili le sessioni online subito dopo questi eventi, in modo da poter recuperare tutto ciò che ho perso (a una velocità maggiore!).<br />
Di recente sono stati pubblicati i video di due eventi recenti:<br />
<h4>
<a href="https://www.droidcon.com/videos?path=San%20Francisco">Droidcon SF</a></h4>
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/100/0*oRf50meaQ2O_VTUT" /></figure><br />
<a href="https://www.sf.droidcon.com/">Droidcon San Francisco</a> si è svolto nell'ultima settimana di novembre e ha trattato numerosi <a href="https://www.droidcon.com/videos?path=San%20Francisco">contenuti Android</a>, dalla UI all'iniezione di dipendenze, dagli strumenti a Kotlin a... molti altri argomenti.<br />
<h4>
<a href="https://www.youtube.com/playlist?list=PLQ176FUIyIUY6SKGl3Cj9yeYibBuRr3Hl">Video Kotlinconf</a></h4>
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/592/0*lIHc4Z1FLXTsAkIn" /></figure><br />
La <a href="https://kotlinconf.com/">KotlinConf</a> si è svolta ai primi di dicembre nella mite Copenaghen. Ci sono state molte sessioni su Android e su Kotlin (comprese le funzionalità relative a linguaggi e multipiattaforma).<br />
<h3>
Podcast ADB</h3>
Dall'ultimo Now su Android sono stati pubblicati un paio di episodi di Android Developers Backstage. Dai un'occhiata ai link seguenti o aprili nel tuo client podcast preferito:<br />
<a href="http://androidbackstage.blogspot.com/2019/12/episode-129-display-input-and-haptics.html">ADB 129: Display, Input, and Haptics</a><br />
<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" src="https://cdn-images-1.medium.com/max/320/0*c04q7vKZt96LRFgu" /></div>
<figcaption style="text-align: center;">Michael, Chet e Romain (non in un pub)</figcaption></figure><br />
In questo episodio, Chet e Romain vanno fino a Londra per fare due chiacchiere con Michael Wright. Non è la prima partecipazione di Michael al podcast e ancora una volta la discussione riguarda display, dispositivi di input e aptiche.<br />
<a href="http://androidbackstage.blogspot.com/2020/01/episode-130-first-law-of-motionlayout.html">ADB 130: First Law of Motion… Layout</a><br />
<br />
<br />
<br />
<figure style="text-align: center;"><img alt="" src="https://cdn-images-1.medium.com/max/320/0*oYsrkX8-ArBbKCmA.jpg" /></figure><br />
In questo episodio, Tor, Romain e Chet chiacchierano con Nicolas Roard e John Hoford del team di Android Studio su Motion Layout - e su ConstraintLayout ed editing visivo nell'IDE.<br />
<h3>
Beh...</h3>
È tutto per ora. Vai a dare un'occhiata ai nuovi documenti su <a href="https://medium.com/androiddevelopers/database-relations-with-room-544ab95e4542">Relazioni in Room</a>, <a href="https://developer.android.com/training/data-storage/room/prepopulate">Prepopolazione in Room</a> e <a href="https://developer.android.com/kotlin/ktx/extensions-list">KTX</a>! Gioca con le <a href="https://developer.android.com/jetpack/androidx/versions/">nuove versioni di AndroidX</a>! Leggi informazioni sull'<a href="https://medium.com/androiddevelopers/room-flow-273acffe5b57">osservazione delle modifiche al database con Room and Flow</a>! Dacci dentro con l'IDE e immergiti in un <a href="https://goo.gle/advanced-coroutines-codelab">codelab su LiveData/coroutine</a>! Prepara i popcorn e guarda tutti i video delle sessioni del <a href="https://www.droidcon.com/videos?path=San%20Francisco">Droidcon SF</a> e della <a href="https://www.youtube.com/playlist?list=PLQ176FUIyIUY6SKGl3Cj9yeYibBuRr3Hl">KotlinConf</a>! Vai ad ascoltare il <a href="http://androidbackstage.blogspot.com/">podcast ADB</a>! E torna presto per non perderti il prossimo aggiornamento dall'universo degli sviluppatori Android.<br />
<!--<meta name="original_url" content="https://medium.com/androiddevelopers/now-in-android-january-8-2020-23ae439e70f1">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-55299773719078925942020-01-15T08:00:00.000+01:002020-01-15T08:00:11.199+01:00Partecipa all'Indie Games Festival di Google Play<em>Pubblicato da Patricia Correa, Director, Developer Marketing</em><br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2fouGfT5HZwNl6Vp1oAu-NNJ4OH0SGVt9HKOZxj7sh7Mryr2XlO8V_osKQ8A2TzC51SqXQeJ8wpIwMHrlkEsv19ZLpWTqvBuAy0fjuql7RGYjVUVShj_K97g1xV9zMixxniYlxhcYIWU/s1600/Android+Developers+Blog+%25281200x600%2529+%25281%2529.png" imageanchor="1"><img alt="Banner Indie Games Festival" border="0" data-original-height="600" data-original-width="1200" id="imgFull" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2fouGfT5HZwNl6Vp1oAu-NNJ4OH0SGVt9HKOZxj7sh7Mryr2XlO8V_osKQ8A2TzC51SqXQeJ8wpIwMHrlkEsv19ZLpWTqvBuAy0fjuql7RGYjVUVShj_K97g1xV9zMixxniYlxhcYIWU/s1600/Android+Developers+Blog+%25281200x600%2529+%25281%2529.png" style="width: 100%;" /></a>
<br />
La community di sviluppatori indipendenti ha pubblicato su Google Play nel 2019 molti titoli fantastici, mostrando l'abilità tecnica e il design innovativo che li rende una parte essenziale del panorama del gaming.
<br />
Per continuare ad aiutare gli sviluppatori indipendenti, oggi annunciamo l'edizione 2020 del nostro annuale <a href="https://g.co/play/indiefestival">Google Play Indie Games Festival</a>. Quest'anno ospiteremo tre concorsi per sviluppatori di diversi paesi europei*, Giappone e Corea del Sud.
<br />
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" id="imgFull" src="https://www.youtube.com/embed/sRPuuu-uyco" width="560"></iframe>
<br />
<h3>
Premi:</h3>
I premi sono pensati per aiutarti a far crescere la tua attività e comprendono:
<br />
<ul>
<li>La possibilità di mettersi in mostra agli eventi finali a Varsavia, Tokyo o Seul
</li>
<li>Promozioni sul Google Play Store
</li>
<li>Promozioni sui nostri canali rivolti ai consumatori e agli sviluppatori
</li>
<li>Accesso a eventi Google esclusivi dedicati agli sviluppatori
</li>
<li>Sessioni di consultazione personalizzate con membri del team di Google
</li>
<li>E altro ancora!
</li>
</ul>
<h3>
Ammissibilità:</h3>
I concorsi sono aperti a sviluppatori di paesi selezionati, con non più di 50 dipendenti. Il gioco inviato deve essere nuovo, rilasciato almeno in open beta tra il <strong>7 maggio 2019</strong> e il <strong>2 marzo 2020</strong>. Gli altri requisiti sono riportati nei termini e condizioni per ciascuno dei concorsi.
<br />
<h3>
Procedura:</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHPtRegfb9M7GylCbgJqPwn_O_PfkkjB6GHrC0Kus1iWiTAxkVYtrnFWTe3A5tOCj7mzqkM4lFJuo_e8n8HqFm87ZpjXqweI1oqTV4mQvCyz7oD6q4sgmrxAUEwfpZt-GMdskoCkvZhhY/s1600/Process+Asset+%25281200x600%2529+v2.png" imageanchor="1"><img alt="banner procedura per Indie Games Festival" border="0" data-original-height="600" data-original-width="1200" id="imgFull" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHPtRegfb9M7GylCbgJqPwn_O_PfkkjB6GHrC0Kus1iWiTAxkVYtrnFWTe3A5tOCj7mzqkM4lFJuo_e8n8HqFm87ZpjXqweI1oqTV4mQvCyz7oD6q4sgmrxAUEwfpZt-GMdskoCkvZhhY/s1600/Process+Asset+%25281200x600%2529+v2.png" style="width: 100%;" /></a>
Compila il modulo facendo clic <a href="https://events.withgoogle.com/indie-games-festival/">qui</a>. Le iscrizioni sono aperte fino al 2 marzo 2020 alle ore 15:00 CET.
<br />
I primi 20 posti in ciascuna regione saranno comunicati a marzo e invitati a partecipare agli eventi del Festival, in cui i partecipanti all'evento, gli esperti del settore e il team di Google sceglieranno i primi 10 classificati. I primi 10 presenteranno i loro giochi sul palco e verranno selezionati i 3 vincitori.
<br />
<h3>
Non hai un gioco da inviare? Vieni a partecipare comunque:</h3>
Anche se non hai inviato un gioco per il concorso, ci piacerebbe vederti in uno degli eventi del Festival il <strong>25 aprile 2020</strong>.
<br />
Scopri di più e iscriviti all'indirizzo <a href="https://events.withgoogle.com/indie-games-festival/">g.co/play/indiefestival</a>
<br />
<em>* Il concorso europeo è aperto agli sviluppatori dei seguenti paesi: Austria, Belgio, Bielorussia, Bulgaria, Croazia, Repubblica Ceca, Danimarca, Estonia, Finlandia, Francia, Germania, Ungheria, Israele, Italia, Lettonia, Lituania, Paesi Bassi, Norvegia, Polonia, Portogallo, Romania, Russia, Slovacchia, Slovenia, Spagna , Svezia, Turchia, Ucraina e Regno Unito (compresa l'Irlanda del Nord).</em>
<br />
<center>
Quanto hai trovato utile questo post del blog?
<br />
<a href="https://docs.google.com/forms/d/e/1FAIpQLScLTlzFd_aV-3rAdBqO1QxwCsuAcDCIM6fJFXyNcyf7zElVXg/viewform?usp=pp_url&entry.753333049=1%E2%98%85+%E2%80%93+Not+at+all&entry.2056663615&entry.646747778=changeme-mm/yy" style="color: gold;">★</a> <a href="https://docs.google.com/forms/d/e/1FAIpQLScLTlzFd_aV-3rAdBqO1QxwCsuAcDCIM6fJFXyNcyf7zElVXg/viewform?usp=pp_url&entry.753333049=2%E2%98%85+%E2%80%93+Not+very&entry.2056663615&entry.646747778=changeme-mm/yy" style="color: gold;">★</a> <a href="https://docs.google.com/forms/d/e/1FAIpQLScLTlzFd_aV-3rAdBqO1QxwCsuAcDCIM6fJFXyNcyf7zElVXg/viewform?usp=pp_url&entry.753333049=3%E2%98%85+%E2%80%93+Somewhat&entry.2056663615&entry.646747778=changeme-mm/yy" style="color: gold;">★</a> <a href="https://docs.google.com/forms/d/e/1FAIpQLScLTlzFd_aV-3rAdBqO1QxwCsuAcDCIM6fJFXyNcyf7zElVXg/viewform?usp=pp_url&entry.753333049=4%E2%98%85+%E2%80%93+Very&entry.2056663615&entry.646747778=changeme-mm/yy" style="color: gold;">★</a> <a href="https://docs.google.com/forms/d/e/1FAIpQLScLTlzFd_aV-3rAdBqO1QxwCsuAcDCIM6fJFXyNcyf7zElVXg/viewform?usp=pp_url&entry.753333049=5%E2%98%85+%E2%80%93+Extremely&entry.2056663615&entry.646747778=changeme-mm/yy" style="color: gold;">★</a>
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcr2Mw7V-Sxv_dsLz6Z8K4qzS0Aw-gIyCAi8VjvlSi_ANauBELmDILI8dZP_w9QT7y4g5S_eqn9GGzReXlHc1JWGCEMMXnNZ1o76xyCOXBdvzzMFvdIQWWToDoZwbQtv7i4Bq6qESTUKg/s1600/play_logo_16_9+%25285%2529.png" imageanchor="1"><img border="0" data-original-height="281" data-original-width="499" id="imgHalf" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcr2Mw7V-Sxv_dsLz6Z8K4qzS0Aw-gIyCAi8VjvlSi_ANauBELmDILI8dZP_w9QT7y4g5S_eqn9GGzReXlHc1JWGCEMMXnNZ1o76xyCOXBdvzzMFvdIQWWToDoZwbQtv7i4Bq6qESTUKg/s1600/play_logo_16_9+%25285%2529.png" style="width: 40%;" /></a>
<br />
</center>
<!--<meta name="original_url" content="http://android-developers.googleblog.com/2020/01/enter-indie-games-festival.html">--><br />Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-16788111032857618692020-01-10T08:00:00.000+01:002020-01-12T22:02:01.528+01:00Relazioni del database con RoomPubblicato da <a class="dc dd bb bc bd be bf bg bh bi gl bl bm gm gn" href="https://medium.com/@florina.muntenescu?source=post_page-----544ab95e4542----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Florina Muntenescu</a><br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="213" src="https://cdn-images-1.medium.com/max/1024/1*_cHB209ZFaz_xKRzJy1_ew.png" width="640" /></div>
<figcaption style="text-align: center;">Relazioni del database: one-to-one, one-to-many, many-to-many</figcaption></figure><br />
Una parte importante della progettazione di un database relazionale è la suddivisione dei dati in tabelle correlate e il loro raggruppamento in modo significativo. A partire da <a href="https://developer.android.com/jetpack/androidx/releases/room#version_220_3">Room 2.2</a> (ora stabile) sono supportate tutte le possibili relazioni tra le tabelle: one-to-one, one-to-many e many-to-many, con una sola annotazione: <a href="https://developer.android.com/reference/android/arch/persistence/room/Relation">@Relation</a>.<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="213" src="https://cdn-images-1.medium.com/max/1024/0*5SACWiK-9zA1-yBQ" width="640" /></div>
<figcaption style="text-align: center;">Relazioni one-to-one</figcaption></figure><br />
<h3>
Relazioni one-to-one</h3>
Ipotizziamo di vivere in un mondo (triste) in cui una persona può possedere un solo cane e un cane può avere un solo proprietario. Questa è una relazione one-to-one. Per modellare questa relazione in un database relazionale, creiamo due tabelle: Dog (Cane) e Owner (Proprietario), in cui la tabella Dog ha un riferimento all'ID Owner o l'Owner ha un riferimento a un ID Dog. In Room, creiamo due entità:<br />
<pre>@Entity
data class Dog(
@PrimaryKey val dogId: Long,
val dogOwnerId: Long,
val name: String,
val cuteness: Int,
val barkVolume: Int,
val breed: String
)</pre>
<pre>@Entity
data class Owner(@PrimaryKey val ownerId: Long, val name: String)</pre>
Ipotizziamo di voler visualizzare sullo schermo l'elenco di tutti i cani e dei loro proprietari. Per farlo, dovremmo creare la classe di dati DogAndOwner:<br />
<pre>data class DogAndOwner(
val owner: Owner,
val dog: Dog
)</pre>
Per eseguire questa query utilizzando SQLite, è necessario 1) eseguire due query, una che ottiene tutti i proprietari e una che ottiene tutti i cani in base agli ID proprietario, e quindi 2) gestire la mappatura degli oggetti.<br />
<pre>SELECT * FROM Owner</pre>
<pre>SELECT * FROM Dog
WHERE dogOwnerId IN (ownerId1, ownerId2, …)</pre>
Per ottenere un List<DogAndOwner> utilizzando Room, non è necessario implementare le due query e gestire la mappatura degli oggetti: è sufficiente utilizzare l'annotazione @Relation.<br />
Nel nostro esempio, poiché Dog ha le informazioni del proprietario, aggiungiamo l'annotazione @Relation alla variabile dog, specificando che la colonna ownerId sul genitore (ovvero l'entità Owner) corrisponde a dogOwnerId:<br />
<pre>data class DogAndOwner(
@Embedded val owner: Owner,
@Relation(
parentColumn = "ownerId",
entityColumn = "dogOwnerId"
)
val dog: Dog
)</pre>
Il nostro <a href="https://developer.android.com/reference/android/arch/persistence/room/Dao">Dao</a> è ora semplificato in:<br />
<pre>@Transaction
@Query("SELECT * FROM Owner")
fun getDogsAndOwners(): List<DogAndOwner></pre>
Nota: poiché Room esegue le due query in secondo piano, aggiungi l'annotazione <a href="https://developer.android.com/reference/android/arch/persistence/room/Transaction">@Transaction</a> per avere la certezza che ciò avvenga atomicamente.<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="213" src="https://cdn-images-1.medium.com/max/1024/0*0Tq1wjjPYFQLSkkF" width="640" /></div>
<figcaption style="text-align: center;">Relazioni one-to-many</figcaption></figure><br />
<h3>
Relazioni one-to-many</h3>
Ipotizziamo che un proprietario possa avere più cani (evvai!): avremmo una relazione one-to-many tra Dog e Owner. Lo schema del database che abbiamo precedentemente definito non cambia: abbiamo ancora le stesse tabelle, poiché la chiave relativa è già nella tabella "many" della relazione.<br />
Per visualizzare l'elenco dei proprietari con i loro cani, dobbiamo creare una nuova classe di dati:<br />
<pre>data class OwnerWithDogs(
val owner: Owner,
val dogs: List<Dog>
)</pre>
Per evitare di eseguire due query separate, possiamo definire una relazione one-to-many tra Dog e Owner, annotando List<Dog> con @Relation come prima:<br />
<pre>data class OwnerWithDogs(
@Embedded val owner: Owner,
@Relation(
parentColumn = "ownerId",
entityColumn = "dogOwnerId"
)
val dogs: <strong>List</strong><Dog>
)</pre>
Il Dao diventa:<br />
<pre>@Transaction
@Query("SELECT * FROM Owner")
fun getDogsAndOwners(): List<OwnerWithDogs></pre>
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="211" src="https://cdn-images-1.medium.com/max/1024/0*t0kcnrKHrjaBGm3u" width="640" /></div>
<figcaption style="text-align: center;">Relazioni many-to-many</figcaption></figure><br />
<h3>
Relazioni many-to-many</h3>
Supponiamo ora di vivere in un mondo perfetto in cui un proprietario può avere più cani e un cane può avere più proprietari. Per modellare questo schema, le nostre tabelle Dog e Owner non sono sufficienti. Poiché un cane può avere più proprietari, è necessario disporre di più voci dello stesso ID Dog, corrispondenti a ID Owner diversi. Poiché dogId è la chiave primaria in Dog, non possiamo inserire più cani con lo stesso ID. Per ovviare a questo, dobbiamo creare una tabella <a href="https://en.wikipedia.org/wiki/Associative_entity">associativa</a> (nota anche come tabella dei riferimenti incrociati) che mantiene le coppie (dogId,ownerId):<br />
<pre>@Entity(primaryKeys = ["dogId", "ownerId"])
data class DogOwnerCrossRef(
val dogId: Long,
val ownerId: Long
)</pre>
Se ora vogliamo ottenere l'elenco di tutti i proprietari con cani: List<OwnerWithDogs>, usando solo query SQLite, dobbiamo scrivere due query: una che ottiene tutti i proprietari e una che unisce le tabelle Dog e DogOwnerCrossRef:<br />
<pre>SELECT * FROM Owner</pre>
<pre>SELECT
Dog.dogId AS dogId,
Dog.dogOwnerId AS dogOwnerId,
Dog.name AS name,
_junction.ownerId
FROM
DogOwnerCrossRef AS _junction
INNER JOIN Dog ON (_junction.dogId = Dog.dogId)
WHERE _junction.ownerId IN (ownerId1, ownerId2, …)</pre>
Per implementarlo in Room, dobbiamo aggiornare la classe di dati OwnerWithDogs e dire a Room che, per ottenere i cani, è necessario utilizzare la tabella associativa DogOwnerCrossRef. Facciamo riferimento alla tabella usando una <a href="https://developer.android.com/reference/androidx/room/Junction">Junction</a>:<br />
<pre>data class OwnerWithDogs(
@Embedded val owner: Owner,
@Relation(
parentColumn = "ownerId",
entityColumn = "dogId",
<strong>associateBy = Junction(DogOwnerCrossRef::class)
</strong>)
val dogs: List<Dog>
)</pre>
Nel nostro Dao, dobbiamo selezionare dai proprietari e restituire la classe di dati corretta:<br />
<pre>@Transaction
@Query("SELECT * FROM Owner")
fun getOwnersWithDogs(): List<OwnerWithDogs></pre>
<h3>
Casi d'uso di relazioni avanzate</h3>
Quando si utilizza l'annotazione @Relation, Room indica l'entità da utilizzare dal tipo della proprietà annotata per impostazione predefinita. Ad esempio, fino ad ora abbiamo annotato un Dog (o un List<Dog>) con @Relation, indicando a Room come modellare la classe e quali colonne interrogare.<br />
Se vogliamo restituire un oggetto diverso, ad esempio un Pup (cucciolo), che non è un'entità ma contiene alcuni dei campi, possiamo specificare l'entità da utilizzare nell'annotazione @Relation:<br />
<pre>data class Pup(
val name: String,
val cuteness: Int = 11
)</pre>
<pre>data class OwnerWithPups(
@Embedded val owner: Owner,
@Relation(
parentColumn = "ownerId",
entity = Dog::class,
entityColumn = "dogOwnerId"
)
val dogs: List<Pup>
)</pre>
Se vogliamo restituire solo colonne specifiche da un'entità, bisogna dire a Room quali sono definendole nella proprietà di proiezione di @Relation. Ad esempio, supponiamo che desideriamo solo ottenere i nomi di tutti i cani nella classe di dati OwnerWithDogs. Dal momento che avremmo bisogno di un List<String>, Room non può dedurre se quelle stringhe corrispondono al nome o alla razza, quindi è necessario specificare la colonna nella proiezione:<br />
<pre>data class OwnerWithDogs(
@Embedded val owner: Owner,
@Relation(
parentColumn = "ownerId",
entity = Dog::class,
entityColumn = "dogOwnerId",
projection = ["name"]
)
val dogNames: List<String>
)</pre>
Se vuoi definire una relazione più stretta tra dogOwnerId e ownerId, indipendentemente dal tipo di relazione che stai creando, usa un vincolo <a href="https://developer.android.com/reference/android/arch/persistence/room/ForeignKey">ForeignKey</a> tra i campi. Tieni presente che le <a href="https://sqlite.org/foreignkeys.html">chiavi esterne di SQLite</a> definiscono indici e possono avere trigger a cascata che aggiornano o eliminano le voci nelle tabelle. Quindi, decidi se desideri utilizzare chiavi esterne se vuoi o meno che questo tipo di funzionalità sia presente nel tuo database.<br />
Sia che tu abbia bisogno del supporto one-to-one, one-to-many o many-to-many, Room è in grado di supportare te (e i tuoi cagnolini) con una sola annotazione: <a href="https://developer.android.com/reference/android/arch/persistence/room/Relation">@Relation</a>. Scopri di più sulle <a href="https://developer.android.com/jetpack/androidx/releases/room#version_220_3">funzionalità di Room 2.2</a> nella nostra presentazione all'Android Dev Summit '19:<br />
<iframe frameborder="0" height="480" scrolling="no" src="https://cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2F_aJsh6P00c0%3Ffeature%3Doembed&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3D_aJsh6P00c0&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2F_aJsh6P00c0%2Fhqdefault.jpg&key=d04bfffea46d4aeda930ec88cc64b87c&type=text%2Fhtml&schema=youtube" width="854"><a href="https://medium.com/media/8caf7668f4751709b4eb606b022f8b17/href">https://medium.com/media/8caf7668f4751709b4eb606b022f8b17/href</a></iframe><!--<meta name="original_url" content="https://medium.com/androiddevelopers/database-relations-with-room-544ab95e4542">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-42337894193383991662020-01-08T08:00:00.000+01:002020-01-08T08:00:22.625+01:00Cloud Firestore ora supporta le query IN!Pubblicato da <span style="font-weight: bold;">Todd Kerpelman, </span><em>Developer Advocate</em><br />
<br />
<em><strong>Nota dell'autore:</strong> queste nuove funzionalità sono disponibili negli SDK iOS e Web a partire da oggi. La libreria Android aggiornata sarà disponibile nei prossimi giorni.</em>
<br />
Ciao, sviluppatore di Cloud Firestore! Volevamo informarti di alcune nuove funzionalità relative alle query che abbiamo aggiunto a <a href="https://firebase.google.com/products/firestore">Cloud Firestore</a> questa settimana che troverai sicuramente utili. Iniziamo con… le query <strong><code>in</code></strong>!
<br />
Con la query <strong><code>in</code></strong>, puoi eseguire una query su un campo specifico per più valori (fino a 10) in una singola query. Per farlo, basta passare un elenco contenente tutti i valori che desideri cercare e Cloud Firestore individuerà tutti i documenti il cui campo è uguale a uno di quei valori.
<br />
<div style="text-align: left;">
Le query <strong><code>in</code></strong> sono un buon modo per eseguire query OR semplici in Cloud Firestore. Ad esempio, se il database della tua app di e-commerce avesse una raccolta <code>customer_orders </code> e volessi sapere quali ordini hanno lo stato "Ready to ship", "Out for delivery" o "Completed", ora potresti acquisire queste informazioni con una singola query, nel modo seguente:
<img alt="Esempio di query IN" border="0" data-original-height="420" data-original-width="800" height="336" id="imgFull" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgzmdceonGRveWRky0jszVgLNeaHeb3lSB9E7A-fSP6aASolD-b_oSquEMBSMAN5M2l7PUtRmUf8wCUvOMFO_e1IEHoDJjw5h69mBvVzfDKn91doytv_QRnnNjW3GI9gnOrRzihzCXb54hR/s640/IN+Query+example.png" width="640" />
</div>
Abbiamo lanciato un'altra funzionalità simile alla query <strong><code>in</code></strong>, la query <strong><code>array-contains-any</code></strong>. Questa funzionalità ti consente di eseguire query <strong><code>array-contains</code></strong> su più valori contemporaneamente.
<br />
Ad esempio, se la tua app avesse una raccolta di prodotti e tali documenti contenessero un array di categorie a cui appartiene ogni articolo, ora potresti cercare gli articoli nella categoria "Appliances" o "Electronics" passando questi valori in una singola query <strong><code>array-contains-any</code></strong>.
<img alt="Esempio array contains any" border="0" data-original-height="420" data-original-width="800" height="336" id="imgFull" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWgxb5BTShX9NZUvohw11GkPm_mHTOWe0iGuNDfrW5lHZln4ntLDG4mjKofLjSbjoM8D1_iluivYCHCUVzw05oeKw6EsrMNVFI3Y0ae09bx9eIYQ6NxfHqBhgZxB2GsPGg1ZBG-ofVyOEG/s640/array-contains-any+example.png" width="640" />
<br />
<div id="imgCaption">
Il documento Baby Monitor verrà restituito solo una volta nella query, anche se corrisponde a più categorie.
</div>
<div style="text-align: center;">
Queste query sono supportate anche nella Console Firebase, che ti consente di provarle sul tuo set di dati prima di iniziare a modificare il codice client.
<img alt="Esempio console" border="0" data-original-height="585" data-original-width="362" id="imgHalf" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPfARTm94P5o834vy-66JgLyg7Mdg0LFeJAb8RS9HYoQQJhpRLC-MitGeEU5FWfUy60L4LQW1BNij4KArQc5zEPmxMc6mmQt4QsDjPyfNexuXqyfrdEVGMlBiZgli_eQlNHffmet-Rly5X/s1600/console-example.png" />
</div>
<div id="imgCaption">
Questo sembra un buon momento per ricordarti che puoi applicare i filtri direttamente nella Console Firebase. Niente male, vero?
</div>
Il comportamento delle regole di sicurezza per queste query è piuttosto semplice. Cloud Firestore esaminerà ogni potenziale valore passato per l'operazione <strong><code>in</code></strong> o <strong><code>array-contains-any</code></strong> e si assicurerà che la query sarebbe consentita per il valore specifico. Se un valore qualsiasi non è consentito, l'intera query ha esito negativo.
<br />
Ad esempio, se il tuo progetto fosse impostato con queste regole di sicurezza...
<br />
<pre class="prettyprint">match /projects/{project} {
allow read: if resource.data.status != "secret";
...
}</pre>
Questa richiesta funzionerebbe...
<br />
<pre class="prettyprint">db.collection("projects").where("status", "in", ["public", "unlisted"]);</pre>
... ma questa fallirebbe, perché è possibile che la nostra query restituisca documenti vietati dalle nostre regole di sicurezza.
<br />
<pre class="prettyprint">db.collection("projects").where("status", "in", ["public", "unlisted", "secret"]);</pre>
<div id="imgCaption">
<em>Non capisci perché non ti inviamo semplicemente i documenti consentiti? Consulta la sezione "Le regole non sono filtri" di <a href="https://youtu.be/eW5MdE3ZcAw?t=823">questo video</a>.</em></div>
Siamo entusiasti di darti la possibilità di sfruttare tutto il potenziale delle query <strong><code>in</code></strong> e <strong><code>array-contains-any</code></strong>, ma devi conoscere alcune importanti limitazioni: <br />
<ul>
<li>Come accennato in precedenza, nelle query al momento hai un limite massimo di 10 valori diversi.
</li>
<li>Puoi avere solo uno di questi tipi di operazioni in una singola query. Tuttavia, puoi combinarli con la maggior parte delle altre operazioni di query.
</li>
</ul>
Ora puoi fare tantissime cose con le query <strong><code>in</code></strong> e non vediamo l'ora di sapere quali nuove funzionalità aggiungerai alle tue app. Assicurati di aver aggiornato le tue librerie client alle ultime versioni per sfruttare al massimo le nuove funzionalità, <a href="https://firebase.google.com/docs/firestore/query-data/queries">consulta la documentazione</a> e buon "databasing"! <!--<meta name="original_url" content="http://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html">--><br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-40597100861869250232020-01-03T08:00:00.000+01:002020-01-03T08:00:04.050+01:00Lezioni apprese dallo sviluppo di ML per il settore sanitario<span class="byline-author">Pubblicato da Yun Liu, Research Scientist e Po-Hsuan Cameron Chen, Research Engineer, Google Health</span> <br />
<br />
I metodi di machine learning (ML) non sono nuovi in medicina: le tecniche tradizionali, come gli alberi decisionali e la regressione logistica, sono state comunemente utilizzate per dedurre regole consolidate relative alla decisione clinica (ad esempio, il <a href="https://www.ncbi.nlm.nih.gov/pubmed/10938172">punteggio di rischio TIMI</a> per stimare il rischio del paziente dopo un evento coronarico). Negli ultimi anni, tuttavia, l'utilizzo del ML è aumentato enormemente per <a href="https://ai.googleblog.com/search/label/Health">diverse applicazioni mediche</a>, come la previsione di eventi avversi da <a href="https://ai.googleblog.com/2018/05/deep-learning-for-electronic-health.html">cartelle cliniche complesse</a> e il <a href="https://ai.googleblog.com/2017/12/deepvariant-highly-accurate-genomes.html">miglioramento dell'accuratezza del sequenziamento genomico</a>. Oltre a rilevare malattie conosciute, i modelli ML possono acquisire informazioni da segnali precedentemente sconosciuti, come <a href="https://ai.googleblog.com/2018/02/assessing-cardiovascular-risk-factors.html">i fattori di rischio cardiovascolare</a> e <a href="https://iovs.arvojournals.org/article.aspx?articleid=2683803">l'errore di rifrazione</a> dalle fotografie del fundus della retina. <br />
<br />
Oltre a sviluppare questi modelli, è importante capire come possono essere incorporati nei flussi di lavoro medici. Ricerche precedenti indicano che i medici assistiti dai modelli ML possono essere più precisi dei medici o dei modelli da soli nella <a href="https://ai.googleblog.com/2018/12/improving-effectiveness-of-diabetic.html">valutazione della retinopatia diabetica</a> e nella <a href="https://ai.googleblog.com/2018/10/applying-deep-learning-to-metastatic.html">diagnosi del carcinoma mammario metastatico</a>. Allo stesso modo, i medici possono <a href="https://ai.googleblog.com/2019/07/building-smily-human-centric-similar.html">sfruttare gli strumenti basati sul ML in modo interattivo</a> per cercare immagini mediche simili, e ciò fornisce ulteriori prove del fatto che i medici possono lavorare efficacemente con strumenti basati sul ML.<br />
<br />
Nel tentativo di migliorare le linee guida per la ricerca nel punto di incontro tra ML e settore sanitario, abbiamo scritto due articoli, pubblicati in <em><a href="https://www.nature.com/nmat/">Nature Materials</a></em> e <em><a href="https://jamanetwork.com/journals/jama">Journal of the American Medical Association</a></em> (<em>JAMA</em>). Il primo è per i professionisti del ML, per consentire loro di capire meglio come sviluppare soluzioni ML per il settore sanitario, e l'altro è per i medici che desiderano una migliore comprensione di come il ML possa aiutarli a migliorare il lavoro clinico. <br />
<br />
<h3>
<strong>How to Develop Machine Learning Models for Healthcare</strong></h3>
Nell'articolo "<a href="https://www.nature.com/articles/s41563-019-0345-0">How to develop machine learning models for healthcare</a>" (<a href="https://rdcu.be/bxGE4">pdf</a>), pubblicato in <em><a href="https://www.nature.com/nmat/">Nature Materials</a></em>, discutiamo dell'importanza di garantire che le esigenze specifiche del settore sanitario siano alla base dello sviluppo di modelli ML per tale ambiente. Ciò dovrebbe avvenire durante tutto il processo di sviluppo delle tecnologie per le applicazioni sanitarie, a partire da selezione dei problemi, raccolta dei dati e sviluppo del modello ML fino a convalida e valutazione, implementazione e monitoraggio.<br />
<br />
La prima considerazione è come identificare un problema sanitario per il quale esista una necessità clinica urgente e per quali previsioni basate sul ML i modelli forniranno informazioni fruibili. Ad esempio, il ML per rilevare la retinopatia diabetica può aiutare ad alleviare il carico di lavoro di screening in alcune parti del mondo in cui il diabete è prevalente e il numero di specialisti è insufficiente. Una volta identificato il problema, si deve fare attenzione con la gestione dei dati, per assicurarsi che le etichette di verità di base, o "standard di riferimento", applicate ai dati siano affidabili e accurate. Ciò può essere ottenuto convalidando le etichette attraverso un confronto dell'interpretazione degli stessi dati da parte di esperti, come le fotografie del fundus della retina, o attraverso una procedura ortogonale, come ad esempio una biopsia per confermare i risultati radiologici. Ciò è particolarmente importante poiché uno standard di riferimento di alta qualità è essenziale sia per l'addestramento di modelli utili sia per la misurazione accurata delle prestazioni dei modelli. Pertanto, è fondamentale che i professionisti del ML lavorino a stretto contatto con esperti clinici per garantire il rigore dello standard di riferimento utilizzato per l'addestramento e la valutazione.<br />
<br />
Anche la convalida delle prestazioni del modello è sostanzialmente diversa nel settore sanitario, perché il problema dello scostamento distributivo può essere marcato. Contrariamente agli studi ML tipici in cui è comune una singola divisione dei test casuale, nel campo medico è importante eseguire la convalida utilizzando più set di dati di valutazione indipendenti, ciascuno con diverse popolazioni di pazienti che possono presentare differenze in termini demografici o sottotipi di malattia. Poiché le specifiche dipendono dal problema, i professionisti del ML devono lavorare a stretto contatto con esperti clinici per progettare lo studio, con particolare attenzione nel garantire che la convalida del modello e le metriche delle prestazioni siano appropriate per il setting clinico specifico.<br />
<br />
L'integrazione degli strumenti di assistenza risultanti richiede inoltre una progettazione ponderata per garantire una perfetta integrazione del flusso di lavoro, tenendo conto della misurazione dell'impatto di questi strumenti sull'accuratezza diagnostica e sull'efficienza del flusso di lavoro. È importante sottolineare che lo studio prospettico di questi strumenti ha un valore sostanziale nella cura reale dei pazienti al fine di comprenderne meglio l'impatto nel mondo reale.<br />
<br />
Infine, anche dopo la convalida e l'integrazione del flusso di lavoro, il percorso verso l'implementazione è solo all'inizio: rimangono da eseguire l'approvazione normativa e il monitoraggio continuo per rilevare modalità di errore impreviste o eventi avversi nell'uso reale.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhq2WIyzrbUu0d5hnAPomMP7rwmNRnpRrjaRH9JPuOb5M7F1eXeZrQev_gZgSm8BdQGdr3ruMN_H_lDFOlnCQb3aWauaTRf_F9NqstFhAg4rYhadB1eLYy8EumQLXt7Y19frcHX76EiJj3r/s1600/image2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="712" data-original-width="969" height="470" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhq2WIyzrbUu0d5hnAPomMP7rwmNRnpRrjaRH9JPuOb5M7F1eXeZrQev_gZgSm8BdQGdr3ruMN_H_lDFOlnCQb3aWauaTRf_F9NqstFhAg4rYhadB1eLYy8EumQLXt7Y19frcHX76EiJj3r/s640/image2.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Due esempi del processo traslazionale di sviluppo, convalida e implementazione di modelli ML per il settore sanitario basati sul nostro lavoro nel rilevare la retinopatia diabetica e il carcinoma mammario metastatico.</td></tr>
</tbody></table>
<h3>
<strong>Consentire ai medici di comprendere meglio il machine learning nel settore sanitario</strong></h3>
In "<a href="https://jamanetwork.com/journals/jama/fullarticle/2754798?guestAccessKey=fd274bef-2813-446f-bb10-e5134640922f">Users’ Guide to the Medical Literature: How to Read Articles that use Machine Learning</a>", pubblicato in <em><a href="https://jamanetwork.com/journals/jama">JAMA</a></em>, riassumiamo i concetti chiave del ML per aiutare i medici a valutare gli studi ML e determinarne l'idoneità di inclusione nel loro flusso di lavoro. L'obiettivo di questo articolo è quello di demistificare il ML, aiutare i medici che hanno bisogno di usare i sistemi ML a comprenderne la funzionalità di base, quando affidarsi a loro e le potenziali limitazioni.<br />
<br />
Le domande centrali che i medici pongono quando valutano qualsiasi studio, sia esso ML o meno, rimangono le seguenti: Lo standard di riferimento era affidabile? La valutazione è stata imparziale, ad esempio ha compreso sia i falsi positivi sia i falsi negativi, e ha incluso un confronto equo con i clinici? La valutazione si applica alla popolazione di pazienti che visito? In che modo il modello ML mi aiuta a prendermi cura dei miei pazienti? <br />
<br />
Oltre a queste domande, i modelli ML dovrebbero anche essere esaminati per determinare se gli iperparametri utilizzati nel loro sviluppo sono stati ottimizzati con un set di dati indipendente rispetto a quello utilizzato per la valutazione del modello finale. Ciò è particolarmente importante, dal momento che un'ottimizzazione inappropriata può portare a una sostanziale sopravvalutazione delle prestazioni, ad esempio un modello sufficientemente complesso può essere addestrato per <a href="https://arxiv.org/abs/1611.03530">memorizzare completamente il set di dati di addestramento</a> e generalizzare male i nuovi dati. Garantire che l'ottimizzazione sia stata eseguita in modo appropriato implica tenere conto delle ambiguità nella denominazione del set di dati e, in particolare, utilizzare la terminologia con cui il pubblico ha più familiarità:<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOoG3qfdZMXVF8CJlcZxp53N5Ks_lG-6b_mXgu8XpLtuIKuNXJEK8SkpoPQMfhk4RFqt7LgOx1CMNecUw13OajxLqDLBaDIrLgXFyaf6BFGcHAo9f70Py3vOtyaKtaLXKumdnDIeFu8r0N/s1600/image1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="373" data-original-width="624" height="382" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOoG3qfdZMXVF8CJlcZxp53N5Ks_lG-6b_mXgu8XpLtuIKuNXJEK8SkpoPQMfhk4RFqt7LgOx1CMNecUw13OajxLqDLBaDIrLgXFyaf6BFGcHAo9f70Py3vOtyaKtaLXKumdnDIeFu8r0N/s640/image1.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">L'incrocio di due campi, ML e settore sanitario, crea ambiguità nel termine "set di dati di convalida". Un set di convalida ML viene in genere utilizzato per fare riferimento al set di dati utilizzato per l'ottimizzazione degli iperparametri, mentre un set di convalida "clinico" viene in genere utilizzato per la valutazione finale. Per ridurre la confusione, abbiamo scelto di fare riferimento al set di convalida (ML) come al set di "ottimizzazione".</td></tr>
</tbody></table>
<h3>
<strong>Uno sguardo al futuro</strong></h3>
È un momento entusiasmante per lavorare sulla AI per il settore sanitario. Il percorso "dal laboratorio al letto del paziente" è lungo e richiede che ricercatori ed esperti di diverse discipline lavorino insieme in questo processo traslazionale. Speriamo che questi due articoli promuovano la comprensione reciproca di ciò che è importante per i professionisti del ML che sviluppano modelli per il settore sanitario e di ciò su cui pongono l'accento i medici che valutano questi modelli, promuovendo così ulteriori collaborazioni tra i due campi verso il raggiungimento di un impatto positivo sulla cura dei pazienti. <br />
<br />
<h3>
<strong>Ringraziamenti</strong></h3>
<em>I principali partecipanti a questi progetti includono Yun Liu, Po-Hsuan Cameron Chen, Jonathan Krause e Lily Peng. Gli autori desiderano ringraziare Greg Corrado e Avinash Varadarajan per i loro consigli e il team di Google Health per il loro supporto.</em><!--<meta name="original_url" content="http://ai.googleblog.com/2019/12/lessons-learned-from-developing-ml-for.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-6961769501290350852020-01-01T08:00:00.000+01:002020-01-01T08:00:02.678+01:00Room Flow<span style="font-weight: normal;">Pubblicato da <a class="dc dd bb bc bd be bf bg bh bi gq bl bm gr gs" href="https://medium.com/@florina.muntenescu?source=post_page-----273acffe5b57----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Florina Muntenescu</a></span><br />
<h3>
<img alt="" height="213" src="https://cdn-images-1.medium.com/max/1024/1*AWxyQ-i-fQGmgLPsTn1PYA.gif" width="640" /></h3>
<br />
Il supporto delle coroutine in Room è aumentato ad ogni rilascio: Room 2.1 ha aggiunto il <a href="https://medium.com/androiddevelopers/room-coroutines-422b786dc4c5">supporto coroutine</a> per le attività di lettura/scrittura in un'unica operazione e con Room 2.2 ora abbiamo il supporto per letture osservabili con <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-flow/">Flow</a>, che consente di ricevere notifiche sulle modifiche nel database.<br />
<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="186" src="https://cdn-images-1.medium.com/max/1024/0*jEnmX0FZOBDdJIHK" width="640" /></div>
<figcaption style="text-align: center;">Supporto per query asincrone in Room</figcaption></figure><br />
<h3>
Flow in azione</h3>
Supponiamo di avere un database di cani, in cui il nome è la chiave primaria, quindi non possiamo avere 2 cani con lo stesso nome nel database.<br />
<pre>@Entity
data class Dog (
@PrimaryKey val name: String,
val cuteness: Int,
val barkingVolume: Int
)</pre>
Per visualizzare un elenco completo di cani con tutte le relative informazioni, scriveremmo una query come questa nel nostro <a href="https://developer.android.com/training/data-storage/room/accessing-data">DAO</a>:<br />
<pre>@Query("SELECT * FROM Dog")
fun getAllDogs(): List<Dog></pre>
Poiché il volume dell'abbaio di un cane può cambiare nel tempo e vogliamo assicurarci che la nostra UI sia aggiornata, vogliamo essere informati di ogni cambiamento che si verifica nella tabella Dogs: nuovi cani aggiunti, cani rimossi o aggiornati. A tale scopo, aggiorniamo la query per restituire Flow:<br />
<pre>@Query("SELECT * FROM Dog")
fun getAllDogs(): <strong>Flow</strong><List<Dog>></pre>
In questo modo, ogni volta che un cane nel database viene aggiornato, l'<strong>intero elenco</strong> di cani viene nuovamente emesso. Ad esempio, supponiamo che nel database siano presenti i seguenti dati:<br />
<pre>(Frida, 11, 3)</pre>
<pre>(Bandit, 12, 5)</pre>
Quando chiamiamo getAllDogs per la prima volta, Flow emetterà:<br />
<pre>[(Frida, 11, 3), (Bandit, 12, 5)]</pre>
Se Bandit si agita e il volume del suo abbaio viene aggiornato a 6: (Bandit, 12, 6), il Flow eseguirà una nuova emissione, con l'intero contenuto della tabella dei cani con i valori più aggiornati:<br />
<pre>[(Frida, 11, 3), <strong>(Bandit, 12, 6)</strong>]</pre>
Ora supponiamo di poter aprire i dettagli di un cane in una nuova schermata. Poiché vogliamo anche assicurarci di disporre sempre dei dati più recenti sul cane e di ricevere aggiornamenti in tempo reale, restituiamo un Flow:<br />
<pre>@Query("SELECT * FROM Dog WHERE name = :name")
fun getDog(name: String): Flow<Dog></pre>
Ora, se chiamiamo getDog("Frida"), Flow restituirà un oggetto: (Frida, 11, 3).<br />
Ogni volta che vengono apportate modifiche alla tabella, indipendentemente da quale riga viene modificata, la query verrà riattivata e Flow verrà nuovamente emesso. Quindi, se Frida viene aggiornato, riceveremo le ultime informazioni.<br />
Tuttavia, questo comportamento del database significa anche che, se aggiorniamo una riga non correlata, come Bandit, il nostro Flow emetterà nuovamente l'elenco, con lo stesso risultato: (Frida, 11, 3). Poiché i trigger del database SQLite consentono solo le notifiche al livello di tabella e non al livello di riga, Room non può sapere esattamente cosa è cambiato nei dati della tabella, quindi riattiva la query definita nel DAO. Nel tuo codice, utilizza gli operatori Flow come <a href="https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/distinct-until-changed.html">distinctUntilChanged</a> per assicurarti di essere informato solo quando vengono cambiati i dati che ti interessano:<br />
<pre>@Dao
abstract class DoggosDao {</pre>
<pre> @Query("SELECT * FROM Dog WHERE name = :name")
abstract fun getDog(name: String): Flow<Dog></pre>
<pre> fun getDogDistinctUntilChanged(name:String) =
getDog(name).distinctUntilChanged()
}</pre>
Inizia a ricevere notifiche sulle modifiche nel tuo database utilizzando letture osservabili con Flow! Insieme ad altro supporto per coroutine aggiunto nelle librerie Jetpack come gli <a href="https://developer.android.com/topic/libraries/architecture/coroutines#lifecycle-aware">ambiti coroutine basati sul ciclo di vita</a>, la <a href="https://developer.android.com/topic/libraries/architecture/coroutines#suspend">sospensione delle coroutine basata sul ciclo di vita</a> o <a href="https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#aslivedata">la trasformazione da </a><a href="https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#aslivedata">Flow a </a><a href="https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary#aslivedata">LiveData</a>, ora puoi utilizzare coroutine e Flow nell'intera applicazione.<br />
Per saperne di più sull'uso di Flow nella tua app, dai un'occhiata a <a href="https://medium.com/androiddevelopers/lessons-learnt-using-coroutines-flow-4a6b285c0d06">questo post</a> sulle lezioni apprese durante l'utilizzo di Flow nell'app Android Dev Summit 2019.<br />
<!--<meta name="original_url" content="https://medium.com/androiddevelopers/room-flow-273acffe5b57">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-39139388966006569022019-12-30T08:00:00.000+01:002019-12-30T08:00:05.382+01:00Il supporto Web per Flutter passa alla beta<em>Pubblicato da Mariam Hasnany, Product Manager, Flutter</em><br />
Siamo lieti di annunciare che il supporto Web per Flutter è ora in versione beta!<br />
<h3>
Perché abbiamo portato Flutter sul Web?</h3>
Gli sviluppatori creano app che devono funzionare sia su dispositivi mobili sia sul Web. Per noi è importante che tu possa progettare e creare ciò che desideri, avendo la certezza che Flutter funzionerà perfettamente ovunque tu ne abbia bisogno. Come sviluppatore, è auspicabile apprendere un singolo insieme di competenze che possono essere facilmente trasferite su più piattaforme. Il supporto Web per Flutter consente agli sviluppatori di utilizzare lo stesso codice, trasferire funzionalità più velocemente e garantire coerenza nelle esperienze offerte su tutti i dispositivi. Inoltre, un potente compilatore Dart per il Web e un'architettura Flutter progettata pensando alla portabilità facilitano la creazione di fantastiche esperienze Web interattive utilizzando Flutter.<br />
<h3>
Più di una semplice anteprima</h3>
Da quando abbiamo rilasciato il supporto Web come <a href="https://medium.com/flutter/bringing-flutter-to-the-web-904de05f0df0">anteprima tecnica</a> al Google I/O quest'anno e dall'inizio del <a href="https://medium.com/flutter/flutter-for-web-early-adopter-program-now-open-9f1fb146e4c4">programma per primi utenti</a> a luglio, abbiamo lavorato duramente per supportare il crescente interesse nell'ampliare il supporto Web di Flutter a Google e al pubblico più ampio.<br />
<h4>
Quindi, cosa significa beta per il Web?</h4>
Con la versione 1.12 di Flutter, il supporto Web di Flutter passa dall'anteprima tecnica alla beta. Quando sei sul canale beta e hai abilitato il supporto Web, la creazione di un nuovo progetto Flutter non include solo le app host Android e iOS, ma ora anche una directory web/ che contiene tutto il necessario per compilare ed eseguire lo stesso codice del progetto in un browser.<br />
Riteniamo che il supporto Web di Flutter stia iniziando ad essere più stabile e gli sviluppatori più avventurosi possono iniziare a utilizzarlo per diversi scenari. Mentre passiamo alla prossima fase di sviluppo, continueremo ad apportare modifiche e a migliorare l'accessibilità, la copertura dei test e altro ancora.<br />
<h3>
Scenari da provare</h3>
Durante lo sviluppo del supporto Flutter per l'esecuzione sul Web, ci siamo concentrati in particolare su una serie di scenari che riteniamo siano adatti alle caratteristiche di Flutter. Riteniamo che il nostro set di funzionalità sia abbastanza completo da consentire agli sviluppatori di creare esperienze Web interattive e avanzate. Lavorando con i nostri primi utenti partner, abbiamo convalidato e perfezionato il supporto per i seguenti scenari.<br />
<strong>App autonoma connessa</strong><br />
Flutter può consentire agli sviluppatori di creare un'unica app dallo stesso codice per esperienze mobile e su browser. <a href="https://startyourjourney.io/">Journey</a>, uno dei nostri primi utenti, ha utilizzato Flutter per creare un'app multipiattaforma.<br />
<br />
<br />
<br />
<figure><img alt="" height="469" src="https://cdn-images-1.medium.com/max/1024/0*E9vaDY0XLc4dCR2J" width="640" /><figcaption>Journey, un'app social, ha recentemente lanciato un'app multipiattaforma utilizzando Flutter</figcaption></figure><br />
Luke O'Brien, fondatore di Journey, afferma "<em>Quattro mesi fa stavo per creare Journey solo per Android per MVP. Ho scoperto Flutter e ho pensato: "È troppo bello per essere vero", ma ho deciso di provare. È stata la decisione migliore che abbia mai preso in vita mia. Flutter ha dimezzato i tempi di sviluppo (probabilmente più che dimezzato) e ora lo abbiamo lanciato su Android, iOS e Web, raddoppiando il potenziale di crescita degli utenti. È difficile descrivere a parole l'impatto che Flutter ha avuto nel trasformare la mia visione in realtà."</em><br />
<strong>Contenuti interattivi incorporati</strong><br />
Uno scenario consiste nell'incorporare una mini app ricca e incentrata sui dati in un sito principale; non sono necessari servizi di navigazione o altre funzionalità simili a quelle delle app. Incorporare un nuovo configuratore di auto, un cruciverba o visualizzazioni interattive di dati in un sito Web esistente sono solo alcuni esempi chiave che si adattano a questo scenario. La <a href="https://studio.aei.dev/showcase/">vetrina di chatbot di AEI Studio</a>, uno dei nostri primi utenti, ha incorporato Flutter nella finestra di dialogo della chat Web che mostrava animazioni, immissione di testo tramite tastiera e altro ancora.<br />
<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" src="https://cdn-images-1.medium.com/max/399/0*M7sTluUPVsk6DcnU" /></div>
<figcaption>Weatherbot è uno dei chatbot di AEI Studio che ha incorporato Flutter nella finestra di dialogo della chat Web</figcaption></figure><br />
<strong>App lite</strong><br />
Anche se il runtime mobile personalizzato di Flutter è in grado oggi di offrire un'esperienza più fluida, a volte l'installazione delle app impedisce agli utenti di iniziare a utilizzarle rapidamente. Un'app Flutter esistente con un'esperienza Web leggera offre alle aziende il meglio di entrambi i mondi. Sebbene l'uso principale dell'app sia su dispositivo mobile, un'app Web lite potrebbe fornire un'esperienza meno ricca di funzionalità, ma con funzionalità correlate utilizzando strumenti, framework, componenti UI e logica di business identici.<br />
<strong>App companion</strong><br />
Un'app companion è un'esperienza Web creata utilizzando Flutter per supportare la tua app mobile di uso principale. Ad esempio, utilizzare Flutter per creare un'app Web che consenta agli amministratori o agli utenti interni di creare contenuti o gestire il backend per l'app mobile Flutter esistente. Sebbene questa app Web sia considerata un'esperienza separata, può sfruttare buona parte del codice dell'app mobile.<br />
<h3>
Sono disponibili i plug-in!</h3>
Flutter ha un concetto di plug-in, che consente di parlare con le librerie native per la piattaforma che stai utilizzando. Quando esegui l'app Flutter sul Web, puoi ottenere l'accesso completo alle librerie JS esistenti. Tutto il codice JS-interop viene gestito dietro le quinte e il plug-in funziona come previsto sia su dispositivo mobile sia sul Web. Abbiamo già implementato molti dei plug-in più richiesti in modo che funzionino in modo coerente nelle app native e su Web. Ora puoi anche <a href="https://medium.com/flutter/how-to-write-a-flutter-web-plugin-5e26c689ea1">scrivere i tuoi plug-in</a>, come hanno fatto <a href="https://github.com/cbenhagen">Ben Hagan</a> per video_player e <a href="https://github.com/lejard-h">Hadrien Lejard</a> per il pacchetto sentry<em>.</em> Sono aggiornati i seguenti pacchetti:<br />
<ul>
<li><a href="https://pub.dev/packages/shared_preferences">shared_preferences</a></li>
<li><a href="https://pub.dev/packages/firebase_core">firebase_core</a></li>
<li><a href="https://pub.dev/packages/firebase_auth">firebase_auth</a></li>
<li><a href="https://pub.dev/packages/google_sign_in">google_sign_in</a></li>
<li><a href="https://pub.dev/packages/google_sign_in">url_launcher</a></li>
<li><a href="https://pub.dev/packages/video_player">video_player</a></li>
<li><a href="https://pub.dev/packages/sentry">sentry</a></li>
</ul>
Abbiamo anche aggiunto nuovi tag e filtri per la piattaforma nel repository del pacchetto pub.dev.<br />
Innanzitutto, nella pagina dei dettagli del pacchetto, sono elencate quali piattaforme supporta il pacchetto. Ciò consente di identificare facilmente se un pacchetto ha supporto Web.<br />
<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="253" src="https://cdn-images-1.medium.com/max/1024/0*5vkz66kMYk5DTfSS" width="640" /></div>
<figcaption><em>Pagina dei dettagli del pacchetto pub.dev che mostra i tag di compatibilità di piattaforma e SDK</em></figcaption></figure><br />
Anche la UI di ricerca ha nuovi filtri, quindi puoi trovare i pacchetti con supporto Web. Tutto questo si basa sui nuovi <a href="https://flutter.dev/docs/development/packages-and-plugins/developing-packages#plugin-platforms">tag manifest della piattaforma</a> ora disponibili in Flutter 1.12.<br />
<br />
<br />
<br />
<figure><div style="text-align: center;">
<img alt="" height="357" src="https://cdn-images-1.medium.com/max/671/0*QApzX3FOYgAGCFRK" width="640" /></div>
<figcaption><em>UI di ricerca pub.dev che mostra il supporto di filtro piattaforma e SDK</em></figcaption></figure><br />
<h3>
Il percorso verso la versione stabile</h3>
Abbiamo fatto molti progressi con la beta, ma abbiamo ancora molto lavoro da fare. Il nostro lavoro sulle prestazioni non è completo e stiamo lavorando per ampliare il nostro ambito di accessibilità, compatibilità del browser e altro ancora.<br />
<strong>Accessibilità</strong><br />
Abbiamo supporto per l'accessibilità sui browser per dispositivi mobili tramite TalkBack su Android e VoiceOver su iOS. Alcune delle funzionalità che sono già implementate per le tecnologie assistive su più piattaforme includono elementi come UI traversal e traversal order, segnali di interazione UI come tappable, label, editable, incremental, image, live region e checkable.<em> </em>Inoltre, stiamo lavorando per aggiungere il supporto dello screen reader per i browser Web desktop.<br />
<strong>Supporto browser</strong><br />
Man mano che Flutter si evolve da un framework solo per dispositivi mobili fino a coprire anche gli idiomi UX desktop, il supporto di Flutter per i browser Web desktop migliorerà e sembrerà più fluido. Abbiamo in programma di supportare e testare Chrome, Edge, Firefox e Safari su browser desktop e mobile.<br />
<strong>Copertura dei test</strong><br />
Dall'anteprima abbiamo aumentato la copertura dei test sia sul framework sia sul motore Web Flutter. Ad oggi, eseguiamo test automatizzati su Chrome e testiamo manualmente Safari. C'è ancora molto lavoro da fare e possiamo imbatterci in regressioni in scenari non testati.<br />
<h3>
Prova il supporto Web di Flutter, contribuisci e condividi!</h3>
Ora è il momento perfetto per provare il supporto Web di Flutter! Vai su flutter.dev/web per iniziare e trovare esempi, documentazione e altro ancora. Se hai già sperimentato il supporto Web di Flutter, puoi <a href="https://github.com/flutter/flutter/wiki/Flutter-build-release-channels">passare al canale beta</a> .<br />
Oggi sono disponibili oltre 1.800 plug-in Flutter; tuttavia, la maggior parte sono per iOS o Android. Puoi aiutare a colmare il divario tra mobile e Web aggiungendo supporto Web ai plug-in esistenti o creando il tuo plug-in. Come guida, abbiamo pubblicato un articolo su <a href="https://medium.com/flutter/how-to-write-a-flutter-web-plugin-5e26c689ea1">come scrivere un plug-in Web</a>.<br />
<h3>
Pensieri finali</h3>
Speriamo che tu sia entusiasta che il supporto Web di Flutter stia avanzando verso il canale beta e che comprenda tutto il nostro impegno per ottenere una versione di qualità del supporto Web da rilasciare in produzione.<br />
Siamo <a href="https://flutter.io/support/">lieti di ricevere feedback</a> e speriamo che condividerai ciò su cui stai lavorando utilizzando l'hashtag #Flutter. Non vediamo l'ora di vedere come stai usando Flutter per creare splendide esperienze Web interattive!<br />
<!--<meta name="original_url" content="https://medium.com/flutter/web-support-for-flutter-goes-beta-35b64a1217c0">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-50868716284124866302019-12-27T08:00:00.000+01:002019-12-27T08:00:07.603+01:00Sviluppo di modelli di deep learning per radiografie del torace con etichette di immagini sottoposte al processo di aggiudicazione<span class="byline-author">Pubblicato da Dave Steiner, MD, Research Scientist and Shravya Shetty, Technical Lead, Google Health</span> <br />
<br />
Con milioni di esami diagnostici eseguiti ogni anno, le radiografie del torace sono uno strumento di imaging clinico importante e accessibile per la diagnosi di molte malattie. Tuttavia, la loro utilità può essere limitata da difficoltà di interpretazione, che richiedono una valutazione rapida e approfondita di un'immagine bidimensionale che raffigura organi tridimensionali e processi patologici complessi. Infatti, esiste il rischio che <a href="https://www.ncbi.nlm.nih.gov/pubmed/12511696">tumori polmonari allo stadio iniziale</a> o <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC3195099/">pneumotorace</a> (collasso dei polmoni) possano non essere rilevati mediante una radiografia del torace, con conseguenti conseguenze molto gravi per i pazienti. <br />
<br />
I progressi nel machine learning (ML) rappresentano un'opportunità entusiasmante per creare nuovi strumenti e aiutare gli esperti a interpretare le immagini mediche. I recenti sforzi hanno mostrato risultati promettenti nel miglioramento della <a href="https://www.blog.google/technology/health/lung-cancer-prediction/">rilevazione del carcinoma polmonare</a> in radiologia, della <a href="https://ai.googleblog.com/2018/11/improved-grading-of-prostate-cancer.html">classificazione del cancro alla prostata</a> in patologia e delle <a href="https://ai.googleblog.com/2018/12/improving-effectiveness-of-diabetic.html">diagnosi differenziali</a> in dermatologia. Per le immagini radiografiche del torace, in particolare, sono a disposizione dei ricercatori di tutte le discipline set di immagini pubblici di grandi dimensioni e de-identificati che hanno supportato diverse <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6245676/">iniziative</a> <a href="https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6245672/">preziose</a> di sviluppo di modelli di deep learning per l'interpretazione delle radiografie. Tuttavia, ottenere etichette cliniche accurate per i set di immagini molto grandi, necessari per il deep learning, può essere difficile. La maggior parte degli sforzi si è concentrata sull'applicazione dell'elaborazione del linguaggio naturale (NLP) basata su regole ai referti radiologici o si è basata sulla revisione delle immagini da parte di singoli refertanti; entrambi gli approcci possono introdurre incoerenze o errori che possono essere particolarmente problematici durante la valutazione del modello. Un'altra sfida riguarda l'assemblaggio di set di dati che rappresentino uno spettro di casi adeguatamente diversificato (ovvero, che garantiscano l'inclusione sia di casi "difficili" sia di casi "facili" e rappresentino l'intero spettro di presentazione della malattia). Infine, alcuni esiti delle radiografie del torace non sono specifici e la loro interpretazione dipende dalle informazioni cliniche sul paziente. Pertanto, la creazione di etichette clinicamente significative e con definizioni coerenti può essere una componente stimolante dello sviluppo di modelli di machine learning che utilizzano come input solo l'immagine. Senza set di dati standardizzati e clinicamente significativi, nonché rigorosi metodi standard di riferimento, l'applicazione corretta dell'ML all'interpretazione delle radiografie del torace sarà ostacolata. <br />
<br />
Per contribuire alla risoluzione di questi problemi, abbiamo recentemente pubblicato l'articolo “<a href="https://pubs.rsna.org/doi/10.1148/radiol.2019191293">Chest Radiograph Interpretation with Deep Learning Models: Assessment with Radiologist-adjudicated Reference Standards and Population-adjusted Evaluation</a>” nella rivista <em><a href="https://pubs.rsna.org/journal/radiology">Radiology</a></em>. In questo studio abbiamo sviluppato modelli di deep learning per classificare quattro esiti clinicamente importanti riscontrati con le radiografie del torace: pneumotorace, noduli e masse, fratture e zone di opacità. Questi esiti target sono stati scelti dopo aver consultato radiologi e colleghi clinici, con lo scopo di focalizzare l'attenzione su condizioni critiche per la cura del paziente e per le quali le sole radiografie del torace sono uno studio di imaging di prima linea importante e accessibile. La scelta di questi esiti ha anche permesso la valutazione del modello usando solo immagini de-identificate senza dati clinici aggiuntivi.<br />
<br />
I modelli sono stati valutati utilizzando migliaia di immagini ottenute da ciascun set di dati per il quale abbiamo raccolto etichette di alta qualità utilizzando un processo di aggiudicazione basato su panel tra radiologi certificati. Quattro radiologi separati hanno inoltre esaminato in modo indipendente le immagini mostrate per confrontare l'accuratezza del radiologo con quella dei modelli di deep learning (usando le etichette delle immagini basate su panel come standard di riferimento). Per tutti e quattro gli esiti e in entrambi i set di dati, i modelli di deep learning hanno dimostrato prestazioni equiparabili a quelle di un radiologo. Come supporto per le ricerche future, le etichette derivanti dal processo di aggiudicazione per i dati disponibili al pubblico sono riportate <a href="https://cloud.google.com/healthcare/docs/resources/public-datasets/nih-chest#additional_labels">qui</a>. <br />
<br />
<h3>
<b>Panoramica dei dati</b></h3>
In questo lavoro sono state impiegate oltre 600.000 immagini provenienti da due set di dati de-identificati. Il primo set di dati è stato sviluppato in collaborazione con i coautori presso gli <a href="https://www.apollohospitals.com/">Apollo Hospitals</a> e consiste in una serie diversificata di radiografie del torace ottenute nel corso di diversi anni da più punti della rete degli Apollo Hospitals. Il secondo set di dati è il set di dati <a href="https://www.nih.gov/news-events/news-releases/nih-clinical-center-provides-one-largest-publicly-available-chest-x-ray-datasets-scientific-community">ChestX-ray14</a>, disponibile al pubblico e rilasciato dal <a href="https://www.nih.gov/">National Institutes of Health</a> (NIH). Questo secondo set di dati ha rappresentato una risorsa importante per molte attività di machine learning, ma <a href="https://arxiv.org/abs/1907.12720">presenta delle limitazioni</a> derivanti da problemi di accuratezza e interpretazione clinica delle etichette attualmente disponibili.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyV1RnqvCN45ee6cTzlpJluYHJBAB1k2Kn-Dc8x0aigZKt4qvPAcloytky6IpfSHzl7fFge_F-W5MCfIztDg6S2pP8ZiYtM6D7Apw45QdWzF__vqI8vV1XlXhL0fhRvBaMzXgPjl6o6AnE/s1600/image1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="683" data-original-width="1368" height="318" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyV1RnqvCN45ee6cTzlpJluYHJBAB1k2Kn-Dc8x0aigZKt4qvPAcloytky6IpfSHzl7fFge_F-W5MCfIztDg6S2pP8ZiYtM6D7Apw45QdWzF__vqI8vV1XlXhL0fhRvBaMzXgPjl6o6AnE/s640/image1.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Radiografia del torace che raffigura uno pneumotorace del lobo superiore sinistro identificato dal modello e dal panel di aggiudicazione, ma non individuato dai singoli radiologi refertanti. <b>A sinistra:</b> L'immagine originale. <b>A destra:</b> La stessa immagine con le regioni più importanti per la previsione del modello evidenziate in arancione.</td></tr>
</tbody></table>
<h3>
<b>Addestramento delle etichette dei set mediante deep learning ed esame visivo delle immagini</b></h3>
Per i set di dati molto grandi costituiti da centinaia di migliaia di immagini, come quelli necessari per addestrare modelli di deep learning altamente precisi, assegnare manualmente le etichette alle immagini non è una soluzione pratica. Pertanto, abbiamo sviluppato un modello separato di deep learning basato su testo per estrarre le etichette delle immagini utilizzando referti radiologici de-identificati associati a ciascuna radiografia. Questo modello di NLP è stato quindi applicato per applicare etichette a oltre 560.000 immagini dal set di dati degli Apollo Hospitals utilizzati per l'addestramento dei modelli di visione artificiale. <br />
<br />
Per ridurre il rumore causato da eventuali errori introdotti dall'estrazione delle etichette basata su testo e anche per fornire etichette pertinenti per un numero sostanziale di immagini ChestX-ray14, i radiologi hanno esaminato visivamente circa 37.000 immagini nei due set di dati. Queste erano separati dalle etichette basate sulla NLP e hanno contribuito a garantire etichette di alta qualità in un set ampio e diversificato di immagini di addestramento.<br />
<br />
<h3>
<b>Creazione e condivisione di etichette standard di riferimento migliorate</b></h3>
Per generare etichette standard di riferimento di alta qualità per la valutazione dei modelli, abbiamo utilizzato un processo di aggiudicazione basato su panel, in base al quale tre radiologi hanno esaminato tutte le immagini del set finali e di test e risolto eventuali disaccordi attraverso la discussione. Ciò ha spesso permesso di identificare e documentare in modo appropriato esiti difficili inizialmente rilevati da un solo radiologo. Per ridurre il rischio di parzialità derivante dalla personalità o dall'anzianità di ogni singolo radiologo, le discussioni si sono svolte in forma anonima tramite un sistema di discussione e aggiudicazione online.<br />
<br />
Poiché la mancanza di etichette aggiudicate disponibili è stato un ostacolo iniziale significativo per il nostro lavoro, <a href="https://cloud.google.com/healthcare/docs/resources/public-datasets/nih-chest#additional_labels">condividiamo con la comunità di ricerca</a> tutte le etichette sottoposte al processo di aggiudicazione per il set di dati ChestX-ray14 disponibile al pubblico, comprendente 2.412 immagini del set di addestramento/convalida e 1.962 immagini del set di test (4.374 immagini in totale). Speriamo che queste etichette facilitino i futuri sforzi nel machine learning e consentano confronti migliori tra modelli di machine learning simili per l'interpretazione delle radiografie del torace. <br />
<br />
<h3>
<b>Uno sguardo al futuro</b></h3>
Questo lavoro presenta diversi contributi: (1) rilascio di etichette sottoposte al processo di aggiudicazione per immagini da un set di dati disponibile al pubblico; (2) un metodo per scalare in modo accurato l'etichettatura dei dati di addestramento utilizzando un modello di deep learning basato su testo; (3) valutazione mediante un set diversificato di immagini con etichette standard di riferimento aggiudicate da esperti; e infine (4) prestazioni paragonabili a quelle dei radiologi dei modelli di deep learning per risultati clinicamente importanti sulle radiografie del torace. <br />
<br />
Tuttavia, per quanto riguarda le prestazioni del modello, raggiungere un'accuratezza media paragonabile a quella degli esperti è solo una parte della storia. Anche se l'accuratezza complessiva per i modelli di deep learning è risultata costantemente simile a quella dei radiologi per ogni esito, le prestazioni nei due set di dati variavano. Ad esempio, la sensibilità nel rilevare uno pneumotorace tra i radiologi era approssimativamente del 79% per le immagini ChestX-ray14, ma era solo del 52% per gli stessi radiologi nell'altro set di dati, suggerendo in quest'ultimo set la presenza di una raccolta di casi di difficoltà maggiore. Ciò evidenzia l'importanza di convalidare gli strumenti di deep learning su più set di dati diversi e, infine, nelle varie popolazioni di pazienti e impostazioni cliniche in cui si intende utilizzare qualsiasi modello. <br />
<br />
Le differenze di prestazioni tra i set di dati sottolineano anche la necessità di set di immagini di valutazione standardizzati, con standard di riferimento accurati, al fine di consentire il confronto tra gli studi. Ad esempio, se due diversi modelli per lo stesso esito venissero valutati utilizzando set di dati diversi, il confronto delle prestazioni avrebbe un valore minimo senza conoscere ulteriori dettagli come la combinazione di casi, le modalità di errore del modello o le prestazioni del radiologo sugli stessi casi. <br />
<br />
Infine, il modello ha spesso identificato esiti che sono stati costantemente non identificati dai radiologi e viceversa. Pertanto, le strategie che combinano le "abilità" uniche dei sistemi di deep learning e degli esperti umani sono probabilmente quelle con le maggiori possibilità di sfruttare al massimo il potenziale delle applicazioni di AI nell'interpretazione delle immagini mediche.<br />
<br />
<h3>
<b>Ringraziamenti</b></h3>
<em>Tra i principali partecipanti a questo progetto di Google ci sono Sid Mittal, Gavin Duggan, Anna Majkowska, Scott McKinney, Andrew Sellergren, David Steiner, Krish Eswaran, Po-Hsuan Cameron Chen, Yun Liu, Shravya Shetty e Daniel Tse. Contributi e input significativi sono stati forniti anche dai collaboratori radiologi Joshua Reicher, Alexander Ding e Sreenivasa Raju Kalidindi. Inoltre, gli autori desiderano ringraziare molti membri del team di radiologia di Google Health tra cui Jonny Wong, Diego Ardila, Zvika Ben-Haim, Rory Sayres, Shahar Jamshy, Shabir Adeel, Mikhail Fomitchev, Akinori Mitani, Quang Duong, William Chen e Sahar Kazemzadeh. Un sincero apprezzamento va anche ai molti radiologi che hanno permesso di realizzare questo lavoro grazie alla loro interpretazione delle immagini nel corso di tutto il progetto.</em><!--<meta name="original_url" content="http://ai.googleblog.com/2019/12/developing-deep-learning-models-for.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-34553408188550715752019-12-25T08:00:00.000+01:002019-12-25T08:00:40.270+01:00Problemi, bug e lavoro pianificatoPubblicato da <a class="gb gc bi bj bk bl bm bn bo bp gd bs bt ge gf" href="https://medium.com/@kf6gpe?source=post_page-----5fb3adab5e25----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">kf6gpe</a><br />
<h3>
Gestione dei feedback in un grande progetto open source come Flutter</h3>
La crescita di Flutter come progetto open source guidato dalla community è motivo di gioia continua per noi di Google. Sia esso misurato in <a href="https://twitter.com/timsneath/status/1189594253690691584">popolarità su GitHub</a>, numero di <a href="https://www.reddit.com/r/FlutterDev/comments/dsnzbq/githubs_2019_octoverse_report_is_out_flutter_is/">progetti creati</a> o <a href="https://adtmag.com/articles/2019/03/29/linkedin-skills.aspx">crescita delle competenze</a>, il 2019 è stato un anno determinante per il progetto e saremo sempre grati a tutti voi per il supporto e i contributi che ci hanno consentito di rendere Flutter il progetto che è oggi. Creiamo Flutter con te e per te e speriamo che questo sia percepibile in tutto ciò che facciamo.<br />
Siamo cresciuti tanto ed è cresciuto anche il numero di problemi di cui dobbiamo tenere traccia! Utilizziamo gli issue su GitHub in vari modi: non solo per segnalare bug, ma per qualsiasi unità di lavoro relativa al progetto. Chiunque può inviare un issue e tali issue rientrano in una serie di categorie:<br />
<ul>
<li>Richieste di funzionalità: cosa un utente o un contributor desidera trovare in Flutter o quali funzionalità migliore.</li>
<li>Richieste di supporto: domande degli utenti su come funziona Flutter o su come eseguire determinate operazioni. Sebbene sia meglio inviare queste richieste su Stack Overflow, molti utenti ci indicano anche come migliorare la nostra documentazione.</li>
<li>Difetti bona fide: cose che non funzionano come dovrebbero. Ciò include gravi problemi come arresti anomali e regressioni delle prestazioni, ma anche quei fastidiosi bug “fit-and-finish” che sono comuni in qualsiasi sistema software di grandi dimensioni.</li>
<li>Elementi non sottoposti a triaging che non sono stati esaminati ed etichettati.</li>
</ul>
Quindi, i nostri issue non sono solo una raccolta di difetti: rappresentano il lavoro che dobbiamo svolgere. Tutto ciò a cui pensiamo di voler lavorare dovrebbe essere indicato come un issue e opportunamente etichettato in modo che, mentre pianifichiamo i nostri obiettivi e i traguardi intermedi, abbiamo un punto da cui partire.<br />
Alcuni progetti utilizzano il numero di bug aperti come indicatori per misurare la qualità delle versioni e classificano i bug come difetti o issue. <a href="https://github.com/flutter/flutter/wiki/Issue-hygiene#issue-philosophy">Flutter non lo fa; scegliamo di tenere traccia di bug e issue allo stesso modo, in GitHub, mantenendo alla luce del sole</a>. Di conseguenza, ci saranno sempre molte più cose su cui <em>potremmo</em> lavorare di quelle sui cui <em>stiamo</em> lavorando. Ciò vale per molti altri progetti open source; basta osservare quelli attivi da un po’ di tempo come <a href="https://github.com/tensorflow/tensorflow/issues">Tensorflow</a>, <a href="https://bugs.chromium.org/p/chromium/issues/list">Chrome</a>, <a href="https://github.com/dart-lang/sdk/issues">Dart</a>, <a href="https://github.com/golang/go/issues">Go</a> o <a href="https://github.com/Microsoft/vscode/issues">VSCode</a>.<br />
Tuttavia, vogliamo essere sicuri che gli issue in arrivo siano ben etichettati e di fare il necessario lavoro di “pulizia” in modo che il nostro database degli issue rifletta accuratamente lo stato del prodotto. A tal fine, abbiamo chiesto aiuto alla community: ci sono diversi volontari che ci supportano per il triage di prima linea e siamo <a href="https://blog.codemagic.io/flutter-and-codemagic-join-forces-on-github/">lieti di annunciare che abbiamo stretto una collaborazione con Nevercode</a>, i fornitori di <a href="https://codemagic.io/">Codemagic</a>, un sistema leader di CI/CD per Flutter, per ulteriore supporto nel triage di prima linea.<br />
<h3>
Il ciclo di vita di un issue</h3>
Siamo sempre pronti a ricevere nuovi issue! Il processo di triaging degli issue è descritto nelle <a href="https://github.com/flutter/flutter/wiki/Triage">Linee guida per il triage</a>. Ecco come funziona in pratica:<br />
Un issue inizia da te: un utente di Flutter o un contributor open source. Dopo averlo presentato (si spera con un caso riproducibile se si tratta di un bug o una descrizione chiara di cosa stai proponendo e perché se è una richiesta di funzionalità), si passa al <em>triage di prima linea</em>.<br />
Nel triage in prima linea, un partecipante alla community (un volontario, qualcuno di Nevercode o un ingegnere che lavora su Flutter) esamina l’issue inviato e pone diverse domande:<br />
<ul>
<li>È definito chiaramente?</li>
<li>Se si tratta di un bug, ha un caso riproducibile e informazioni sufficienti per essere portato avanti?</li>
<li>Se si tratta di un miglioramento delle funzionalità, siamo in grado di comprendere sufficientemente ciò che stai chiedendo in modo da poter valutare il suo contributo alla piattaforma?</li>
<li>È un duplicato di un issue già presentato?</li>
</ul>
Mentre eseguiamo queste attività, il triage di prima linea applica quante più etichette possibile all’issue. Utilizziamo queste etichette in molti modi, ad esempio per stabilire la priorità, determinare come inoltrare un issue a un determinato team e se includerlo nel prossimo milestone. Utilizziamo le query di GitHub e alcuni strumenti personalizzati per analizzare gli issue e individuare eventuali segnali su ciò che la community sta cercando e perché.<br />
Da qui, si passa al <em>triage secondario</em>, in cui un team assegnato esamina l’issue e pone domande, ad esempio se l’issue può essere inserito nel lavoro in corso e quando è possibile pianificare il completamento del lavoro. Anche in questa fase possono essere aggiungete o modificate etichette, in quanto le etichette ci forniscono le migliori istantanee possibili sul lavoro che vogliamo portare a termine e su chi può farlo.<br />
Infine, un ingegnere si offre di lavorare sull’issue. A differenza di molti progetti software, in genere non assegniamo gli issue ai contributor: indipendentemente dal fatto che un contributor lavori per Google o meno, sono i contributor che si offrono di risolvere gli issue, non vengono loro assegnati dal lavoro che abbiamo pianificato. Consentendo agli sviluppatori di offrirsi, distribuiamo il bilanciamento del carico ai singoli contributor; ogni contributor si auto-assegna solo gli issue su cui sta lavorando attivamente e fornisce milestone a tali issue in modo che sappiamo quando finiranno sul ramo master. Ovviamente, i lead possono chiedere a determinate persone di lavorare sugli issue, ma il più delle volte è solo una richiesta di aiuto, non un ultimatum o un incarico.<br />
Una volta che un issue è stato completato con nostra soddisfazione, viene chiuso. Spesso questo include un link alla richiesta pull che risolve l’issue, ma un issue può essere chiuso anche per altri motivi, tra cui:<br />
<ul>
<li>È una richiesta di supporto? Indirizziamo l’utente che ha inviato la richiesta verso un canale di supporto come la mailing list <a href="mailto:flutter-dev@googlegroups.com">flutter-dev@googlegroups.com</a>, il <a href="https://reddit.com/r/flutterdev">r/FlutterDev</a> Reddit, le nostre community Discord (<a href="https://discordapp.com/invite/N7Yshp4">chat utente</a>, <a href="https://github.com/flutter/flutter/wiki/Chat">chat community</a> utilizzata principalmente dai contributor) oppure <a href="https://stackoverflow.com/tags/flutter">Stack Overflow</a>.</li>
<li>È un issue duplicato? Prima di chiuderlo, inseriamo un link all’issue originale, aggiornando anche tale issue.</li>
<li>L’issue ha informazioni sufficienti per essere riprodotto e siamo riusciti a riprodurlo? In caso contrario, è possibile che non possiamo fare nulla se non chiuderlo.</li>
</ul>
<h3>
I nostri progressi finora</h3>
Come puoi immaginare, poiché la nostra popolarità è cresciuta, anche il numero di issue aperti e chiusi è aumentata <a href="http://github.com/flutter/flutter">github.com/flutter/flutter</a> (questo contiene tutti gli issue tranne quelli relativi al sito Web, registrati in <a href="http://github.com/flutter/website">github.com/flutter/website</a>):<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/616/1*D_MCtnl2h_spFgoORikDcA.png" /><figcaption>Bug chiusi o aperti in base ai fine mese da gennaio 2018</figcaption></figure><br />
Altrettanto entusiasmante è il numero di issue che <em>non</em> reca un'etichetta corrispondente a uno dei nostri team di triage secondari, come ad esempio <a href="https://github.com/flutter/flutter/labels/framework">framework</a>, <a href="https://github.com/flutter/flutter/labels/engine">engine</a> o <a href="https://github.com/flutter/flutter/labels/plugin">plugin</a>:<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/615/1*9ZXPKWTBT01b_6zsFtundg.png" /><figcaption>Issue non etichettati per il triage secondario, marzo 2019-oggi</figcaption></figure><br />
Puoi vedere chiaramente dove abbiamo iniziato a coinvolgere Nevercode nel nostro processo di triage, all'inizio di settembre, avendo ottenuto grandi progressi già da metà settembre.<br />
Questa enfasi sul triage riflette il nostro obiettivo: non avere zero issue <em>aperti,</em> ma avere zero issue <em>senza etichetta</em> in modo da avere segnali adeguati dalla nostra community e poter definire le giuste priorità al lavoro da completare. Mentre Flutter continua a crescere in popolarità, prevediamo una crescita continua del numero di issue aperti che richiedono il triage, molti dei quali saranno richieste di nuove funzionalità da parte della community. Continueremo a utilizzare le etichette per determinare quali sono i bug che richiedono attenzione immediata, quali quelli che possiamo rinviare alla prossima versione beta o stabile e quali sono le nuove richieste di funzionalità.<br />
<h3>
Come puoi aiutarci</h3>
Puoi aiutarci a mantenere il nostro database degli issue pulito e ordinato inviando issue utili. Quando invii un issue, ricorda quanto segue:<br />
<ul>
<li>Non utilizzare GitHub per richieste di supporto. Come parte del triage degli issue, ora chiudiamo le richieste di supporto inviate in GitHub, reindirizzando le persone verso canali migliori. In quei canali probabilmente troverai qualcuno in grado di rispondere alla tua domanda e le domande e le risposte sono più facili da individuare anche per gli altri utenti.</li>
<li>Invia casi riproducibili: se è un tuo issue, assicurati che ce ne sia realmente uno. Anche se non è un tuo issue, valuteremo volentieri anche casi riproducibili inviati da te! Scrivere casi riproducibili per i bug è un ottimo modo per iniziare a imparare a usare Flutter con esempi reali.</li>
<li>Aggiorna e vota gli issue importanti per te.</li>
<li>Contribuisci ai casi di test nel repository Flutter. Questo è un altro modo per migliorare la tua conoscenza di Flutter e interagire con la community. Ci aiuta inoltre a prevenire le regressioni: mentre tutto il nuovo codice è accompagnato da casi di test, come buona pratica ci impegniamo anche ad aumentare la copertura dei test. Se sei interessato a contribuire in questo modo, puoi dare un'occhiata agli issue con l'etichetta <a href="https://github.com/flutter/flutter/labels/a%3A%20tests">a: tests</a>.</li>
<li>Puoi aiutarci con il triaging di issue presentati da altri utenti.</li>
</ul>
Siamo profondamente grati per il supporto e la fiducia che ci hai dimostrato nell'investire il tuo tempo e le tue idee applicative con Flutter. Accogliamo con favore il coinvolgimento della community, sia che si tratti di inviare bug o richieste di funzionalità o di creare una richiesta pull per rendere Flutter la piattaforma con cui desideri lavorare. Grazie!<br />
<!--<meta name="original_url" content="https://medium.com/flutter/https-medium-com-flutter-issues-bugs-and-backlogs-5fb3adab5e25">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-80375421605736386672019-12-23T08:00:00.000+01:002019-12-23T08:00:02.469+01:00DevKids: conosciamo meglio i bambini del DevFest
<style>code { background-color: transparent }</style>
<img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifS7HXNMCdZffh9IHBXgOe_1zDG-yHPkpsMI72ZLxKDrWgPllvm-V1Qt6fLkcY2T2QGfGFXHp005PINTpgy6MRl4aloyZhphRILVpDOyTQznugJViWgQKFvrv0eeLutoEu_4IreVkuBOc/s1600/devfest+banner.png" style="display: none;" />
<img alt="Banner DevFest" border="0" data-original-height="396" data-original-width="1600" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEifS7HXNMCdZffh9IHBXgOe_1zDG-yHPkpsMI72ZLxKDrWgPllvm-V1Qt6fLkcY2T2QGfGFXHp005PINTpgy6MRl4aloyZhphRILVpDOyTQznugJViWgQKFvrv0eeLutoEu_4IreVkuBOc/s640/devfest+banner.png" width="640" />
<br />
Dopo che Aaron Ma, un relatore DevFest di 11 anni, ha recentemente condiviso con noi <a href="https://developers.googleblog.com/2019/11/young-devfest-speaker-and-organizer-talk-tech.html">i suoi consigli sulla programmazione</a>, le persone hanno continuato a chiederci: "A cosa stanno lavorando gli altri bambini del DevFest?" Per rispondere a tutte le domande ricevute, vogliamo mostrarti come questi incredibili bambini, o DevKids come ci piace chiamarli, stanno presentando le loro idee agli eventi DevFest in tutto il mondo.<br />
<br />
Di seguito troverai le storie di DevKids dal Marocco a Toronto, che hanno parlato di argomenti che vanno dalla robotica alla realtà aumentata. Ci auguriamo che ti piacciano le loro storie!<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTeqH7mDXpReBDlsOEOhtdMDTyySKEKGzecaAggmJMG7iqt0hr4LeaXhDHzYQcOZ6OS8B8JmAKgFvmM6OhDs6KF-BWaW7dnq6l_IO9oD1jNfhNwrOh1bV43ja_tPmgENRIUTOF4_Z07PY/s1600/ider.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Ider, sviluppatore di 11 anni dal Marocco" border="0" data-original-height="639" data-original-width="960" height="213" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTeqH7mDXpReBDlsOEOhtdMDTyySKEKGzecaAggmJMG7iqt0hr4LeaXhDHzYQcOZ6OS8B8JmAKgFvmM6OhDs6KF-BWaW7dnq6l_IO9oD1jNfhNwrOh1bV43ja_tPmgENRIUTOF4_Z07PY/s320/ider.jpg" width="320" /></a></div>
<br />
<b>Ider, uno sviluppatore di 11 anni dal Marocco</b>, è appassionato di Python e non ha paura di usarlo. Con una comprensione incredibilmente avanzata del machine learning e della realtà aumentata, gli è stato chiesto di parlare al <a href="https://www.meetup.com/GDGAgadir/events/254253618/">DevFest Agadir</a> su cosa riservi il futuro per i bambini interessati alla programmazione.<br />
<br />
La presentazione di Ider si intitolava "The Talk of The Next Generation" ed era incentrata su come i bambini possano scoprire la loro passione per l'informatica e iniziare a costruire un futuro che un giorno sperano diventi realtà. <br />
<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoxPJPCcuAtkAFxKYv1KEr0MoFCAnqqmA3_s8_sfYTNXqW1utN2uNrKGpSh8YyiSIiCyFq1rB-cOg1nmhvvWuGf2BHql4e4zWabBkoF2t7KVGTY1FRJ31W2MITO4_4QduJEc512xGL-qM/s1600/selin.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Selin, sviluppatrice di 13 anni di Istanbul" border="0" data-original-height="1003" data-original-width="1080" height="297" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjoxPJPCcuAtkAFxKYv1KEr0MoFCAnqqmA3_s8_sfYTNXqW1utN2uNrKGpSh8YyiSIiCyFq1rB-cOg1nmhvvWuGf2BHql4e4zWabBkoF2t7KVGTY1FRJ31W2MITO4_4QduJEc512xGL-qM/s320/selin.jpeg" width="320" /></a></div>
<br />
<div>
<div>
<b>Selin, una sviluppatrice di 13 anni di Istanbul, </b>a cui è stato riconosciuto il titolo di <a href="http://adaawards.com/">European Digital Girl of the Year</a> da AdaAwards, si è unita alla famiglia DevFest la scorsa stagione. Di recente, in un <a href="https://devfest.istanbul/">evento DevFest a Istanbul</a>, ha raccontato di come ha scoperto la sua passione per la robotica: attraverso una presentazione intitolata <em>My Journey of Building Robots</em>. Appassionata di Python, Java e Ruby, ha spiegato come sta usando le sue abilità per costruire un cane guida robotico per non vedenti. Spera, con l'aiuto della tecnologia, di poter creare un nuovo mondo più accessibile per le persone con disabilità.</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br />
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEWpSVi9DQiJCkl0oz-j0kNwEnCjzEjAwgisuqrqyd82m5iBrxGSdZoYGTbTIk8mPha2nF6HZo0eM_jwIZz7xQbLuTQhMa-jz6HagCgOAtPySkY1QaOGBwZCZjzRbM_rbBfXaZUaq7F5s/s1600/radostin.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Radostin, programmatore di 13 anni della Bulgaria" border="0" data-original-height="200" data-original-width="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEWpSVi9DQiJCkl0oz-j0kNwEnCjzEjAwgisuqrqyd82m5iBrxGSdZoYGTbTIk8mPha2nF6HZo0eM_jwIZz7xQbLuTQhMa-jz6HagCgOAtPySkY1QaOGBwZCZjzRbM_rbBfXaZUaq7F5s/s1600/radostin.jpeg" /></a></div>
<div>
<div>
<br />
<b>Radostin, un programmatore di 13 anni dalla Bulgaria</b>, è entrato a far parte della famiglia DevFest la scorsa stagione come relatore ed è ora un membro chiave del DevFest Organizing Team. Di recente ha creato un'app per il team che raccoglie i feedback su diversi eventi DevFest. </div>
<div>
<br /></div>
<div>
Ha tenuto qualche tempo fa un intervento al <a href="https://devfest.bg/">DevFest Sofia</a> parlando di come ha creato un'app che insegna alle persone a giocare a scacchi su Assistente Google. Il giovane sviluppatore ha anche parlato di come sua zia lo abbia introdotto alla programmazione e di come osservarla programmare lo abbia ispirato ad imparare Java, Kotlin, C#, Python, Dart e C++. Ha terminato la sua presentazione raccontando di lunghe notti trascorse a guardare video di YouTube, alla ricerca di cose sempre nuove da imparare. Radostin ha ispirato la sua famiglia DevFest a credere di poter imparare qualsiasi cosa, ovunque e in qualsiasi momento. </div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnTeaGMd9O0XejZ4396m-0c9PJG46hKT9k71mDtbLwXqk4fc7bQTzc7-9b8NvtE1_FG-j4VSQAvo2_SGSicm4aNs1DdzEFFiBtwmjRDMl1Iu47JDzV69YEdt6BqOPFwJmoPvB543FaiR4/s1600/artash.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Artash (12 anni) e Arushi (9 anni), fratello e sorella, sono un team di programmatori del Canada" border="0" data-original-height="1195" data-original-width="1600" height="239" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnTeaGMd9O0XejZ4396m-0c9PJG46hKT9k71mDtbLwXqk4fc7bQTzc7-9b8NvtE1_FG-j4VSQAvo2_SGSicm4aNs1DdzEFFiBtwmjRDMl1Iu47JDzV69YEdt6BqOPFwJmoPvB543FaiR4/s320/artash.JPG" width="320" /></a></div>
<div>
<div>
<b><br /></b> <b>Artash (12 anni) e Arushi (9 anni), fratello e sorella, sono un team di programmatori del Canada</b>. Al <a href="https://www.meetup.com/GDG-Cloud-Toronto/events/262981054/">DevFest Toronto</a> hanno presentato il loro robot di riconoscimento facciale che utilizza il machine learning per rilevare le emozioni del volto. La loro presentazione ha incluso anche dimostrazioni dal vivo in cui il robot ha analizzato alcuni partecipanti al DevFest e ha dato risposte fisiche alle loro emozioni. I due programmatori emergenti hanno anche descritto come hanno creato il loro algoritmo ML per costruire il robot. </div>
<div>
<br /></div>
<div>
Cosa li ha ispirati ad avviare un simile progetto? Il viaggio spaziale. Artash e Arushi credono che, poiché gli astronauti intraprenderanno missioni spaziali sempre più lunghe, sia importante costruire strumenti che possano monitorare la loro salute mentale. Sperano che un giorno il loro robot accompagnerà gli astronauti nel primo viaggio su Marte.</div>
</div>
<div>
<br /></div>
<br />
<br />
<em>Ti senti ispirato da questi ragazzi fantastici? Vuoi condividere le tue idee con una comunità accogliente? Trova un DevFest vicino a te, all’indirizzo <a href="https://www.blogger.com/devfest.withgoogle.com">devfest.withgoogle.com</a>.</em>
<!--<meta name="original_url" content="http://developers.googleblog.com/2019/11/devkids-inside-look-at-kids-of-devfest.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-50592354836248592922019-12-20T08:00:00.000+01:002019-12-20T08:00:01.478+01:003 cose da sapere su Android Studio dall'Android Dev Summit 2019<em>Pubblicato da Deepanshu Madan, Product Manager </em>
<br />
Durante l'<a href="https://developer.android.com/dev-summit">#AndroidDevSummit</a> non sono mancati <a href="https://android-developers.googleblog.com/2019/10/android-dev-summit-2019-keynote.html">gli annunci</a> e le notizie tecniche... così tante informazioni che non saremmo sorpresi se ti fossi perso qualcosa. Quindi analizzeremo gli elementi chiave discussi durante il summit, in modo da essere certi che non ti sia sfuggito nulla. Oggi ci concentriamo su <strong>Android Studio</strong>, analizzando le prime tre cose che dovresti sapere:
<br />
<h3>
<strong>1. Supporto per Jetpack Compose</strong></h3>
Per la migliore esperienza di sviluppo con <a href="https://developer.android.com/jetpack/compose">Jetpack Compose</a>, ora puoi utilizzare l'ultima versione di <a href="https://developer.android.com/studio/preview">Android Studio 4.0 nel canale canary</a> e trarre vantaggio dalle funzionalità intelligenti dell'editor, come i modelli New Project, il completamento del codice e la possibilità di visualizzare immediatamente l'anteprima della UI di Jetpack Compose.
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_kPYMjabefJmGAyjdrD6DrZePo3nek94MTEB2pQwR9oysrJBqKFCpGUb9D6As8mKEFxjdRVqp0F2rYxIDkVpqp7OXjq2ZEI0V1mFTv9yDuI5HG4Ru_wwczTvk5iAVB1WU9WLoObwoNfU/s1600/image1.png" imageanchor="1"><img border="0" data-original-height="1026" data-original-width="1600" height="410" id="imgFull" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_kPYMjabefJmGAyjdrD6DrZePo3nek94MTEB2pQwR9oysrJBqKFCpGUb9D6As8mKEFxjdRVqp0F2rYxIDkVpqp7OXjq2ZEI0V1mFTv9yDuI5HG4Ru_wwczTvk5iAVB1WU9WLoObwoNfU/s640/image1.png" width="640" /></a>
<br />
<h3>
<strong>2. Novità nella sessione di Android Studio</strong></h3>
Abbiamo trattato sia le nuove funzionalità sia i successi della nostra iniziativa sulla qualità, <a href="https://android-developers.googleblog.com/2019/08/android-studio-35-project-marble-goes.html">Project Marble</a>. Per quanto riguarda la qualità, analizziamo i miglioramenti relativi a blocchi e latenza, rilevamento di perdite di memoria, dimensionamento dell'heap in IDE automatico e velocità di creazione. Inoltre, durante la sessione troverai demo su nuovi sviluppi e funzionalità in Android Studio, come ad esempio lo strumento Build Attribution che ti aiuta a capire e diagnosticare i problemi con il tuo sistema di compilazione, desugar della libreria Java 8, View binding, modelli live Android di Kotlin, un Layout inspector live aggiornato che consente di esplorare le risorse direttamente dalla vista per trovare l'origine del valore di una proprietà nel codice sorgente con una visualizzazione 3D della gerarchia della vista.
<br />
<br />
<center>
<iframe allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" frameborder="0" height="315" src="https://www.youtube.com/embed/XPMrnR1_Biw" width="560"></iframe></center>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUnlYRrkab9UOcYn8UfP6Z2A-LG4yfA7iedaLU5JKe6JbX7dCid9zBN3UDk_Q1TljA2T8_xvqhyphenhyphenJapCzEjbt0MLYi5I89pgr1D7IU5tF3004n2zRIqUidQV5KRvkQRiHJx0dAAmiNVftc/s1600/image3.png" imageanchor="1"><img border="0" data-original-height="804" data-original-width="1600" height="321" id="imgFull" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUnlYRrkab9UOcYn8UfP6Z2A-LG4yfA7iedaLU5JKe6JbX7dCid9zBN3UDk_Q1TljA2T8_xvqhyphenhyphenJapCzEjbt0MLYi5I89pgr1D7IU5tF3004n2zRIqUidQV5KRvkQRiHJx0dAAmiNVftc/s640/image3.png" width="640" /></a>
<br />
<h3>
<strong>3. Strumenti di progettazione di Android Studio</strong></h3>
Abbiamo introdotto nuove funzionalità dell'editor di layout e navigazione, tra cui una nuova visualizzazione divisa, nuovi strumenti come l'anteprima multipla che consente di visualizzare il layout in diverse configurazioni e MotionEditor, editor di visual design per il tipo di layout MotionLayout, che semplifica la creazione e la visualizzazione in anteprima delle animazioni. Motion Editor fornisce una semplice interfaccia per manipolare elementi dalla libreria MotionLayout che funge da base per l'animazione nelle app Android. Nelle versioni precedenti, la creazione e la modifica di questi elementi richiedevano la modifica manuale dei vincoli nei file di risorse XML. Ora, Motion Editor può generare questo XML per te, con il supporto per gli stati di inizio e fine, fotogrammi chiave, transizioni e linee temporali.
<br />
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirvoyGsNS79xQIdOOCjj6rrj24OtC4pZglKM3TSFEWshQqs_1E9A2vYFJpZMskWwiAhABHzgBQq4lQG35jCQokPgmsJylulIR5AZg6l2u2o-TUYCZrXdS8GAJJUu8j8DEuDnVZ_3cWQDM/s1600/image2.gif" imageanchor="1"><img border="0" data-original-height="845" data-original-width="1036" height="522" id="imgHalf" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirvoyGsNS79xQIdOOCjj6rrj24OtC4pZglKM3TSFEWshQqs_1E9A2vYFJpZMskWwiAhABHzgBQq4lQG35jCQokPgmsJylulIR5AZg6l2u2o-TUYCZrXdS8GAJJUu8j8DEuDnVZ_3cWQDM/s640/image2.gif" width="640" /></a>
<br />
<a href="https://www.youtube.com/watch?v=5jJ-e278BFY&list=PLWz5rJ2EKKc_xXXubDti2eRnIKU0p7wHd">L'intera playlist delle sessioni e dei video di Android Dev Summit è disponibile qui</a>. Continueremo a parlare di altri elementi chiave, quindi <a href="https://android-developers.googleblog.com/">tieni gli occhi aperti</a> e <a href="https://twitter.com/androiddev">segui AndroidDevelopers su Twitter</a>. Grazie mille per averci permesso di vivere questa esperienza con te!
<br />
<!--<meta name="original_url" content="http://android-developers.googleblog.com/2019/11/3-things-to-know-about-android-studio.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-24499531840881602012019-12-19T14:00:00.000+01:002019-12-19T14:00:09.380+01:00Nuove soluzioni per la gravità quantistica con TensorFlow<span class="byline-author">Pubblicato da Thomas Fischbacher, Researcher in Compression, Google Research, Zurigo</span> <br />
<br />
I recenti progressi della ricerca sul machine learning (ML) hanno portato allo sviluppo di strumenti utili per problemi di ricerca che vanno ben oltre l'ambito per cui sono stati progettati. Ora si inizia a realizzare il valore di questi strumenti quando vengono applicati ad argomenti vari, come <a href="https://ai.googleblog.com/2019/03/unifying-physics-and-deep-learning-with.html">insegnare ai robot come lanciare</a> o prevedere le <a href="https://ai.googleblog.com/2019/10/learning-to-smell-using-deep-learning.html">proprietà olfattive delle molecole</a> . Ispirati da progressi come questi, ci siamo lanciati nella sfida di applicare <a href="https://www.tensorflow.org/">TensorFlow</a>, una piattaforma informatica normalmente utilizzata per ML, per migliorare la comprensione della fisica fondamentale. <br />
<br />
Forse il più grande problema ancora aperto nella fisica teorica fondamentale potrebbe essere questo: la nostra attuale comprensione della <a href="https://en.wikipedia.org/wiki/Quantum_mechanics">meccanica quantistica</a> include solo tre delle quattro forze fondamentali: la forza <a href="https://en.wikipedia.org/wiki/Electromagnetism">elettromagnetica</a>, le forze <a href="https://en.wikipedia.org/wiki/Strong_interaction">forti</a> e quelle <a href="https://en.wikipedia.org/wiki/Weak_interaction">deboli</a>. Al momento non esiste una teoria quantistica completa che includa anche la forza di <a href="https://en.wikipedia.org/wiki/Gravity">gravitazione</a>, pur confermando le osservazioni sperimentali, ovvero un modello accurato di <a href="https://en.wikipedia.org/wiki/Quantum_gravity">gravità quantistica</a>. <br />
<br />
Un approccio promettente a un modello unificato che includa la gravità quantistica, sopravvissuta a numerosi controlli di coerenza matematica, è la <a href="https://en.wikipedia.org/wiki/M-theory">M-Theory</a> o la "<a href="http://www.damtp.cam.ac.uk/research/gr/public/qg_ss.html">Teoria precedentemente nota come teoria delle stringhe"</a>, introdotta nel 1995 da <a href="https://en.wikipedia.org/wiki/Edward_Witten">Edward Witten</a>. Nel mondo di tutti i giorni, sperimentiamo tutte e quattro le dimensioni: tre dimensioni spaziali (<em>x</em>, <em>y</em>e <em>z</em>), più il tempo (<em>t</em>). La M-Theory prevede che, a brevissimo termine, l'Universo sarà descritto, invece, da undici dimensioni. Ma, come si può immaginare, la connessione tra il mondo a quattro dimensioni che osserviamo e il mondo a 11 dimensioni previsto dalla M-Theory è estremamente difficile da determinare analiticamente. In effetti, potrebbe richiedere una manipolazione analitica di equazioni con più termini di quanti sono gli elettroni nell'Universo. <br />
<br />
Quest'estate abbiamo pubblicato un <a href="https://arxiv.org/abs/1906.00207">articolo</a> nel <em><a href="https://link.springer.com/article/10.1007/JHEP08(2019)057">Journal of High Energy Physics</a></em> in cui abbiamo presentato nuovi modi per affrontare tali problemi attraverso l'uso creativo della tecnologia ML. Usando le semplificazioni possibili grazie a TensorFlow, siamo riusciti a portare il numero totale di soluzioni di equilibrio (stabile o instabile) note per un particolare tipo di geometrie dello spaziotempo della M-Theory <a href="https://arxiv.org/abs/1909.10969">a 194</a>, tra cui un nuovo universo modello quadridimensionale <a href="https://en.m.wikipedia.org/wiki/Tachyonic_field">senza tachioni</a>. Le geometrie che abbiamo studiato sono speciali, in quanto sono ancora (a malapena) accessibili con calcoli esatti che non richiedono di ignorare termini potenzialmente importanti. Abbiamo anche pubblicato un breve tutorial <a href="https://research.google.com/seedbank/seed/so_supergravity_extrema">Google Colab</a> e una più potente <a href="https://github.com/google-research/google-research/tree/master/m_theory">libreria Python</a> da impiegare nelle ricerche correlate. <br />
<br />
<h3>
<strong>Applicazione di TensorFlow alla M-Theory</strong></h3>
Questo lavoro si basa su un'osservazione chiave secondo la quale un approccio numerico e analitico misto può essere più potente di un metodo puramente analitico. Invece di tentare di trovare soluzioni analitiche con la forza bruta, utilizziamo un approccio numerico che sfrutta TensorFlow per la ricerca iniziale di soluzioni al modello. Ciò produce quindi ipotesi su quali combinazioni specifiche possono essere testate e analizzate con rigorosi metodi matematici, dimostrando in definitiva l'esistenza effettiva di una soluzione congetturata. Ciò rappresenta una nuova metodologia per compiere ulteriori progressi nella fisica teorica.<br />
<br />
<h3>
<strong>Conclusioni</strong></h3>
Ci auguriamo che questi risultati rappresentino un passo importante nell'interpretazione della M-Theory e dimostrino come la comunità di ricerca possa utilizzare i nuovi strumenti ML, come TensorFlow, per affrontare altri problemi altrettanto complessi. Stiamo già applicando i metodi appena scoperti in ulteriori ricerche di fisica teorica. <br />
<br />
<h3>
<strong>Ringraziamenti</strong></h3>
<em>Questa ricerca è stata condotta da Iulia M. Comşa, Moritz Firsching e Thomas Fischbacher. Ulteriori ringraziamenti vanno a Jyrki Alakuijala, Rahul Sukthankar e Jay Yagnik per l'incoraggiamento e il supporto.</em><!--<meta name="original_url" content="http://ai.googleblog.com/2019/11/new-solutions-for-quantum-gravity-with.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-62558689373766610392019-12-18T14:15:00.000+01:002019-12-18T14:18:02.320+01:00Da provare: Usa Firebase per ospitare la tua app Flutter sul WebPubblicato da <a class="fc fd bi bj bk bl bm bn bo bp fe bs bt ff fg" href="https://medium.com/@clocksmith?source=post_page-----852ee533a469----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Anthony Robledo</a><br />
<br />
<figure><img alt="" height="408" src="https://cdn-images-1.medium.com/max/1024/1*eL-dHo08RwyLYOl17DNTog.png" width="640" /></figure><br />
Hai un'app Flutter e vuoi mostrarla al mondo? Non cercare oltre! Questo tutorial mostra come ospitare la tua app Flutter sul Web tramite un URL ospitato da Firebase in 4 semplici passaggi (2 passaggi se hai già installato firebase-tools e hai un progetto Firebase esistente). Partiamo dal presupposto che Flutter sia installato e che sia possibile eseguire l'app Flutter localmente. Se non conosci Flutter, dai prima un'occhiata alla <a href="https://flutter.dev/docs/get-started/install">guida introduttiva</a>.<br />
<h3>
Requisito preliminare</h3>
Passa al canale dev e abilita il Web se non l'hai già fatto:<br />
<pre>$ flutter channel dev
$ flutter upgrade
$ flutter config — enable-web</pre>
Se il progetto è stato creato prima di Flutter Web, ha bisogno di una copia della cartella Web con un file index.html. Se nella Root directory non è presente una cartella Web, esegui il comando seguente per crearne una:<br />
<pre>$ flutter create .</pre>
Se crei un progetto dopo aver abilitato il Web, il file web/index.html viene creato automaticamente. Bene, ora passiamo alla configurazione di Firebase Hosting.<br />
☝️Nota: i passaggi 1 e 2 possono essere saltati se hai già un progetto Firebase e firebase-tools installati.<br />
<h3>
Passaggio 1. Crea il progetto Firebase</h3>
♀ Salta questo passaggio se hai già un progetto Firebase da usare.<br />
☝️Nota: puoi creare un nuovo progetto anche da riga di comando nel passaggio 2, ma questo tutorial lo crea nella Console Firebase.<br />
Da un browser, accedi alla <a href="https://console.firebase.google.com/">Console Firebase</a>.<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*J0ZaW4hZbSlEXjK9" /></figure><br />
Fai clic su <strong>Add project</strong> e dai un nome al tuo progetto:<br />
<br />
<br />
<figure><img alt="" height="348" src="https://cdn-images-1.medium.com/max/1024/0*0i_W2vNozOa87N_B" width="640" /></figure><br />
☝️Nota: al nome del progetto potrebbero essere aggiunti alcuni caratteri extra alla fine affinché il nome sia univoco.<br />
Fai clic su <strong>Continue.</strong> Per semplicità, non abilitare Google Analytics per questo progetto: disattiva l'opzione e fai clic su <strong>Create project</strong>. Se desideri utilizzare Google Analytics, lascia l'interruttore selezionato. Dovrai eseguire un ulteriore passaggio per scegliere o creare un progetto Google Analytics.<br />
<br />
<br />
<figure><img alt="" height="500" src="https://cdn-images-1.medium.com/max/1024/0*qUlFDIP4H0C4_urO" width="640" /></figure><br />
Attendi alcuni secondi per la creazione del progetto. Quando è pronto, fai clic su <strong>Continue.</strong><br />
<br />
<br />
<figure><img alt="" height="640" src="https://cdn-images-1.medium.com/max/810/0*fL_0E_cbbMff5IIr" width="569" /></figure><br />
Il passaggio 1 è completato!<br />
<h3>
Passaggio 2. Installa l'interfaccia a riga di comando firebase-tools</h3>
♀ Salta questo passaggio se hai già installato firebase-tools.<br />
Se non hai npm, devi prima installarlo.<br />
☝️Nota: se non sai se npm è installato sul tuo computer, esegui $ npm -v e vedi se viene elencato un numero di versione. In caso affermativo, hai già npm. Se invece vedi "comando non trovato", devi installarlo.<br />
<a href="https://www.guru99.com/download-install-node-js.html">Installazione di npm su Windows</a>.<br />
<a href="https://docs.npmjs.com/downloading-and-installing-node-js-and-npm">Installazione di npm su Linux</a>.<br />
<a href="https://treehouse.github.io/installation-guides/mac/node-mac.html">Installazione di npm su Mac</a>.<br />
Oppure scaricalo direttamente da <a href="https://nodejs.org/">Node.js</a>.<br />
Una volta installato npm, esegui il comando seguente per installare firebase-tools:<br />
<pre>$ npm install -g firebase-tools</pre>
firebase-tools è installato!<br />
<h3>
Passaggio 3. Inizializza l'hosting Firebase per il tuo progetto Flutter</h3>
Apri un terminale e vai alla Root directory per la tua app Flutter ed esegui questo comando per accedere:<br />
<pre>$ firebase login</pre>
☝️Nota: se hai già effettuato l'accesso e desideri accedere nuovamente con un account diverso, disconnettiti prima con:<br />
<pre>$ firebase logout</pre>
Segui la riga di comando e il link nel tuo browser. Accetta le autorizzazioni facendo clic su <strong>Ok</strong>. Ora dovresti vedere dal terminale che l'accesso è stato effettuato:<br />
<br />
<br />
<figure><img alt="" height="162" src="https://cdn-images-1.medium.com/max/718/0*JZ_gkqDtOFpGnTtJ" width="640" /></figure><br />
Ora esegui questo comando dalla Root directory dell'app Flutter per inizializzare il tuo progetto Firebase:<br />
<pre>$ firebase init</pre>
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*F4TQYa2f-9bAaW3X" /></figure><br />
Utilizza i tasti freccia per spostare il cursore su <strong>Hosting</strong> e premi la barra spaziatrice per selezionarlo, quindi premi Invio. Ora vedrai questa schermata:<br />
<br />
<br />
<figure><img alt="" height="158" src="https://cdn-images-1.medium.com/max/1024/0*KnlTgdXeNMDAMpna" width="640" /></figure><br />
Seleziona <strong>Use an existing project</strong> premendo Invio. Utilizza i tasti freccia per selezionare il progetto realizzato nel passaggio 1.<br />
Quindi, inserisci build/web come directory pubblica e premi Invio, quindi inserisci <strong>y</strong> (per yes, "sì") per selezionare l'opzione dell'app per pagina singola:<br />
<br />
<br />
<figure><img alt="" height="139" src="https://cdn-images-1.medium.com/max/1024/0*mYMsKK4g65KGh71f" width="640" /></figure><br />
☝️Nota: dopo questo passaggio, vengono creati 2 nuovi file (.firebaserc e firebase.json) nella Root directory. Controlla e assicurati che siano lì. In caso contrario, verifica la presenza di errori nel passaggio di inizializzazione di Firebase e riprova.<br />
<h3>
Passaggio 4. Crea e distribuisci!</h3>
Crea la tua app per il Web:<br />
<pre>$ flutter build web</pre>
Questo crea i file necessari in <root-directory>/build/web.<br />
Nota: se viene visualizzato l'avviso: “Experimental feature web is not supported on stable branches”, assicurati di essere almeno sul canale dev e di avere il Web abilitato. Ad esempio:<br />
<pre>$ flutter channel
beta
* dev
master
stable
$ ~ $ flutter devices
2 connected devices:</pre>
<pre>Chrome • chrome • web-javascript • Google Chrome 78.0.3904.87
Web Server • web-server • web-javascript • Flutter Tools</pre>
Infine, esegui:<br />
<pre>$ firebase deploy</pre>
I file di hosting vengono caricati e ospitati nel tuo URL Firebase. Puoi seguire il link nel tuo terminale per il tuo progetto Web Flutter!<br />
<!--<meta name="original_url" content="https://medium.com/flutter/must-try-use-firebase-to-host-your-flutter-app-on-the-web-852ee533a469">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-72681403780833722162019-12-09T08:00:00.000+01:002019-12-09T08:00:11.917+01:00Utilizzo di TensorFlow 2 per elaborazione del linguaggio naturale all'avanguardia<h2>
<b>Hugging Face: elaborazione del linguaggio naturale all'avanguardia in dieci righe di TensorFlow 2.0</b></h2>
<em><br /></em>
<em>Pubblicato da </em><a class="da db bb bc bd be bf bg bh bi fm bl bm de df" href="https://medium.com/@lysandrejik?source=post_page-----102445cda54a----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Lysandre Debut</a><br />
<em><br /></em>
<em>Hugging Face è una startup NLP leader, con oltre mille aziende che utilizzano la sua libreria in produzione, tra le quali troviamo Bing, Apple e Monzo. </em><strong><em>Tutti gli esempi utilizzati in questo tutorial sono disponibili su Colab. I link sono disponibili nelle sezioni corrispondenti.</em></strong><br />
<br />
<br />
<figure style="text-align: center;"><img alt="" height="353" src="https://cdn-images-1.medium.com/max/1024/1*7i5LhQ33_EdxMaPu3iteQg@2x.png" width="640" /></figure><br />
<h3>
<strong>Introduzione</strong></h3>
Hugging Face è una startup incentrata sulla NLP con una grande community open source, in particolare intorno alla libreria <a href="https://github.com/huggingface/transformers">Transformers</a>. /Transformers è una libreria basata su Python che espone un'API per utilizzare molte architetture transformer note, come <strong>BERT</strong>, <strong>RoBERTa</strong>, <strong>GPT-2</strong> o <strong>DistilBERT</strong>, che ottengono risultati all'avanguardia su una varietà di attività di NLP come la classificazione del testo, l'estrazione delle informazioni, la risposta alle domande e la generazione di testo. Queste architetture vengono fornite pre-addestrate con diversi set di pesi. Per muovere i primi passi con Transformers è necessario installare solo il pacchetto pip:<br />
<pre>pip install transformers</pre>
La libreria ha visto una crescita superveloce in PyTorch ed è stata recentemente trasferita su TensorFlow 2.0, offrendo un'API che ora funziona con l'API fit di Keras, TensorFlow Extended e TPU. Questo post del blog è dedicato all'utilizzo della libreria Transformers tramite TensorFlow: usare l'API di Keras e la TPUStrategy TensorFlow per mettere a punto un modello Transformer all'avanguardia.<br />
<h3>
Libreria e filosofia</h3>
Transformers si basa sul concetto di modelli transformer pre-addestrati. Questi modelli transformer sono disponibili in diverse forme, dimensioni e architetture e hanno modi specifici di accettare i dati di input: tramite la tokenizzazione.<br />
La libreria si basa su tre classi principali: una classe di configurazione, una classe tokenizer e una classe modello.<br />
<ul>
<li><strong>La classe configuration: </strong>la classe configuration ospita informazioni rilevanti relative al modello che useremo, come il numero di livelli e il numero di punti di attenzione. Di seguito è riportato un esempio di un file di configurazione BERT, per i pesi pre-addestrati bert-base-cased. Le classi configuration ospitano questi attributi con vari metodi di I/O e proprietà dei nomi standardizzate.</li>
</ul>
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">{
"attention_probs_dropout_prob": 0.1,
"hidden_act": "gelu",
"hidden_dropout_prob": 0.1,
"hidden_size": 768,
"initializer_range": 0.02,
"intermediate_size": 3072,
"max_position_embeddings": 512,
"num_attention_heads": 12,
"num_hidden_layers": 12,
"type_vocab_size": 2,
"vocab_size": 28996
}</pre>
<ul>
</ul>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/fbc4e947327509f8a10f2c46002020e0/href">https://medium.com/media/fbc4e947327509f8a10f2c46002020e0/href</a></iframe><br />
<ul>
<li><strong>La classe tokenizer</strong>:<strong> </strong>la classe tokenizer si occupa di convertire la stringa di Python in array o tensori di numeri interi che sono indici in un vocabolario modello. Ha molte funzioni utili che ruotano attorno alla tokenizzazione di una stringa in token. Questa tokenizzazione varia in base al modello, quindi ogni modello ha il proprio tokenizer.</li>
<li><strong>La classe model:</strong> la classe model contiene la logica di modellazione delle reti neurali. Quando si utilizza un modello TensorFlow, eredita da tf.keras.layers.Layer, il che significa che può essere utilizzata molto semplicemente dall'API fit di Keras o addestrata utilizzando un ciclo di addestramento personalizzato e GradientTape.</li>
</ul>
<h3>
Gioia nella semplicità</h3>
Il vantaggio dell'utilizzo di Transformers risiede nell'API di facile utilizzo indipendente dal modello. Il caricamento di un modello pre-addestrato, insieme al relativo tokenizer, può essere eseguito con poche righe di codice. Ecco un esempio di caricamento dei modelli BERT e GPT-2 TensorFlow e dei loro tokenizer:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">from transformers import (TFBertModel, BertTokenizer,
TFGPT2Model, GPT2Tokenizer)
bert_model = TFBertModel.from_pretrained("bert-base-cased") # Automatically loads the config
bert_tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
gpt2_model = TFGPT2Model.from_pretrained("gpt2") # Automatically loads the config
gpt2_tokenizer = GPT2Tokenizer.from_pretrained("gpt2")</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/7ab04fc38cbf2651152aa50b17df00b7/href">https://medium.com/media/7ab04fc38cbf2651152aa50b17df00b7/href</a></iframe><br />
I pesi vengono scaricati dal bucket S3 di HuggingFace e memorizzati nella cache locale sulla macchina. I modelli sono pronti per essere utilizzati per inferenza o ottimizzati, se necessario. Vediamolo in azione.<br />
<h3>
Ottimizzazione di un modello Transformer</h3>
L'ottimizzazione di un modello è semplificata grazie ad alcuni metodi disponibili nella libreria Transformer. Le parti successive sono creare nel mondo seguente:<br />
<ul>
<li>Caricamento dei dati di testo e pre-elaborazione</li>
<li>Definizione degli iperparametri</li>
<li>Addestramento (con Keras su CPU/GPU e con TPUStrategy)</li>
</ul>
<h4>
Creazione di una pipeline di input</h4>
Abbiamo realizzato un <a href="https://colab.research.google.com/drive/1l39vWjZ5jRUimSQDoUcuWGIoNjLjA2zu">notebook colab</a> per consentirti di procedere rapidamente nella scrittura del codice. Sfrutteremo il pacchetto<a href="https://www.tensorflow.org/datasets/">tensorflow_datasets</a> per il caricamento dei dati. Tensorflow-dataset ci fornisce un <a href="https://www.tensorflow.org/api_docs/python/tf/data/Dataset">tf.data.Dataset</a>, che può essere inserito nel nostro <a href="https://huggingface.co/transformers/main_classes/processors.html#transformers.data.processors.glue.glue_convert_examples_to_features">metodo glue_convert_examples_to_features</a>.<br />
Questo metodo utilizzerà il tokenizer per tokenizzare l'input e aggiungere token speciali all'inizio e alla fine delle sequenze (come [SEP], [CLS], </s> o <s>, ad esempio) se tali token aggiuntivi sono richiesti dal modello. Questo metodo restituisce un tf.data.Dataset che contiene gli input caratterizzati.<br />
Possiamo quindi mescolare questo set di dati e raggrupparlo in batch di 32 unità usando i metodi standard tf.data.Dataset.<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">import tensorflow_datasets
from transformers import glue_convert_examples_to_features
data = tensorflow_datasets.load("glue/mrpc")
train_dataset = data["train"]
validation_dataset = data["validation"]
train_dataset = glue_convert_examples_to_features(train_dataset, bert_tokenizer, 128, 'mrpc')
validation_dataset = glue_convert_examples_to_features(validation_dataset, bert_tokenizer, 128, 'mrpc')
train_dataset = train_dataset.shuffle(100).batch(32).repeat(2)
validation_dataset = validation_dataset.batch(64)</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/fda0e93b3a54edfc85ee81b1b5d75857/href">https://medium.com/media/fda0e93b3a54edfc85ee81b1b5d75857/href</a></iframe><br />
<h4>
Addestramento con il metodo fit di Keras</h4>
Addestrare un modello usando il metodo fit di Keras non è mai stato così semplice. Ora che abbiamo la configurazione della pipeline di input, possiamo definire gli iperparametri e chiamare il metodo fit di Keras con il nostro set di dati.<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">optimizer = tf.keras.optimizers.Adam(learning_rate=3e-5, epsilon=1e-08, clipnorm=1.0)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')
bert_model.compile(optimizer=optimizer, loss=loss, metrics=[metric])
bert_history = bert_model.fit(
bert_train_dataset,
epochs=2,
steps_per_epoch=115,
validation_data=bert_validation_dataset,
validation_steps=7
)</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/c4c1e4f63aacf71e0863c56f4aabd79e/href">https://medium.com/media/c4c1e4f63aacf71e0863c56f4aabd79e/href</a></iframe><br />
<h4>
Addestramento con Strategy</h4>
L'addestramento con una strategia ti dà un migliore controllo su ciò che accade durante la sua esecuzione. Passando da una strategia all'altra, l'utente può selezionare la modalità distribuita in cui il modello viene addestrato: da multi-GPU a TPU.<br />
Nel momento in cui viene scritto questo post, <a href="https://www.tensorflow.org/api_docs/python/tf/distribute/experimental/TPUStrategy">TPUStrategy</a> è l'unico modo infallibile per addestrare un modello su una TPU usando TensorFlow 2. A tal proposito, creare un ciclo personalizzato usando una strategia ha ancora più senso, poiché le strategie possono essere facilmente commutate e l'addestramento su multi-GPU non richiederebbe praticamente alcuna modifica del codice.<br />
La creazione di un loop personalizzato richiede un po' di configurazione, pertanto ti consigliamo di consultare il seguente notebook colab per acquisire una migliore comprensione dell'argomento. Il documento non entra nel dettaglio della tokenizzazione come il primo colab, ma <strong>mostra come creare una pipeline di input che verrà utilizzata da TPUStrategy.</strong><br />
<strong>Utilizza il bucket di Google Cloud Platform come mezzo per ospitare i dati</strong>, poiché le TPU sono complicate da gestire quando si utilizzano file system locali. <em>Il </em><a href="https://colab.research.google.com/drive/1yWaLpCWImXZE2fPV0ZYDdWWI8f52__9A#scrollTo=mnhwpzb73KIL"><em>notebook colab è disponibile qui</em></a><em>.</em><br />
<h4>
Ora Transformers ha accesso alle API TensorFlow... e quindi?</h4>
Il principale punto di forza della libreria Transformers è la sua API semplice e indipendente dal modello. Agendo come front-end per i modelli che ottengono risultati all'avanguardia nella NLP, passare da un modello all'altro in base al compito da svolgere è estremamente semplice.<br />
Ad esempio, ecco lo script completo per ottimizzare BERT su un'attività di classificazione linguistica (MRPC):<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">model = TFBertForSequenceClassification.from_pretrained("bert-base-cased")
tokenizer = BertTokenizer.from_pretrained("bert-base-cased")
data = tensorflow_datasets.load("glue/mrpc")
train_dataset = data["train"]
train_dataset = glue_convert_examples_to_features(train_dataset, tokenizer, 128, 'mrpc')
optimizer = tf.keras.optimizers.Adam(learning_rate=3e-5, epsilon=1e-08, clipnorm=1.0)
loss = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True)
metric = tf.keras.metrics.SparseCategoricalAccuracy('accuracy')
model.compile(optimizer=optimizer, loss=loss, metrics=[metric])
model.fit(train_dataset, epochs=3)</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/33ad175ce13adda7617db781867a3373/href">https://medium.com/media/33ad175ce13adda7617db781867a3373/href</a></iframe><br />
Tuttavia, in un ambiente di produzione, la memoria è scarsa. Sarebbe consigliabile usare un modello più piccolo (passare ad esempio a DistilBERT). Per farlo, ti basta cambiare le prime due righe con queste altre due:<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;">model = TFDistilBertForSequenceClassification.from_pretrained("distilbert-base-uncased")
tokenizer = DistilbertTokenizer.from_pretrained("distilbert-base-uncased")</pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/772c31c23c14727b116b2354e8a8c3f9/href">https://medium.com/media/772c31c23c14727b116b2354e8a8c3f9/href</a></iframe><br />
Come piattaforma che ospita oltre 10 architetture Transformer, /Transformers semplifica l'utilizzo, l'ottimizzazione e il confronto dei modelli che hanno cambiato l'aspetto del deep learning per il campo NLP. Funge da backend per molte app downstream che sfruttano i modelli trasformer ed è utilizzato in produzione da molte aziende. Puoi inviarci qualsiasi domanda o problema tramite il nostro <a href="https://github.com/huggingface/transformers/issues/new/choose">repository GitHub</a>.<br />
<!--<meta name="original_url" content="https://medium.com/tensorflow/using-tensorflow-2-for-state-of-the-art-natural-language-processing-102445cda54a">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-92181185075388458932019-12-06T08:00:00.000+01:002019-12-06T08:00:01.295+01:00Sottotitoli sul dispositivo con Live Caption<span class="byline-author">Pubblicato da Michelle Tadmor-Ramanovich and Nadav Bar, Senior Software Engineers, Google Research, Tel-Aviv</span> <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxLR0ae3CKbMIPvEjJavQTTCYFN6saPKSRd0iNNKt6cmQMhIQ8iznG0pDFtMAuviEdhk2YKPuiJPDAVqjk-krROdDq_rBN4H4xdhR_76TF0F0EBkV4sJ_ddvbyorwJ8llo2Ez7sML6Q0Xv/s1600/Google_Live_Caption_keyword_2880x1200.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="667" data-original-width="1600" height="266" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjxLR0ae3CKbMIPvEjJavQTTCYFN6saPKSRd0iNNKt6cmQMhIQ8iznG0pDFtMAuviEdhk2YKPuiJPDAVqjk-krROdDq_rBN4H4xdhR_76TF0F0EBkV4sJ_ddvbyorwJ8llo2Ez7sML6Q0Xv/s640/Google_Live_Caption_keyword_2880x1200.png" width="640" /></a></div>
I sottotitoli per i contenuti audio sono fondamentali per gli utenti non udenti e ipoudenti, ma possono migliorare l'esperienza di qualsiasi utente. Guardare video senza audio è pratica comune, in treno, durante le riunioni, a letto o quando i bambini dormono, e studi hanno dimostrato che i sottotitoli possono aumentare la durata del tempo che gli utenti trascorrono a guardare un video di quasi il <a href="https://www.businesswire.com/news/home/20090325005658/en/PLYmedia-Subtitles-Increase-Online-Video-Viewing-40">40%</a>. Tuttavia, il supporto per i sottotitoli è frammentato tra le varie app e persino al loro interno, determinando l'inaccessibilità di una quantità significativa di contenuti audio, come blog live, podcast, video personali, messaggi audio, social media e altro ancora.<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/v8cLk2W3vY8/0.jpg" frameborder="0" height="360" src="https://www.youtube.com/embed/v8cLk2W3vY8?feature=player_embedded" width="640"></iframe></div>
Di recente abbiamo introdotto <a href="https://blog.google/products/android/live-caption/">Live Caption</a>, una nuova funzionalità Android che sottotitola automaticamente i contenuti multimediali riprodotti sul telefono. I sottotitoli vengono aggiunti in tempo reale, interamente sul dispositivo, senza utilizzare risorse di rete, preservando così la privacy e riducendo la latenza. Questa funzionalità è attualmente disponibile su Pixel 4 e Pixel 4 XL, verrà implementata sui modelli Pixel 3 entro la fine dell'anno e sarà presto disponibile su altri dispositivi Android.<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJYr4tkbx3qTUpvDCTHo2ugqwrbAQmRfJTDv-XEhMI9VJYVpLFztWsrx-ESaKuolg01IT5y7OfI-vS2Jkf605tUw0Wp7ZSP4zmFXsxjug-_GxQjNv_smy4bK1IyMgvTuYoCqygWcFzFxJg/s1600/image2.gif" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="600" data-original-width="600" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJYr4tkbx3qTUpvDCTHo2ugqwrbAQmRfJTDv-XEhMI9VJYVpLFztWsrx-ESaKuolg01IT5y7OfI-vS2Jkf605tUw0Wp7ZSP4zmFXsxjug-_GxQjNv_smy4bK1IyMgvTuYoCqygWcFzFxJg/s400/image2.gif" width="400" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Durante la riproduzione di contenuti multimediali, è possibile avviare Live Caption con un solo tocco dal controllo del volume e visualizzare così la casella dei sottotitoli sullo schermo.</td></tr>
</tbody></table>
<h3>
<strong>Live Caption: creata per garantire precisione ed efficienza</strong></h3>
Live Caption funziona attraverso una combinazione di tre modelli di deep learning su dispositivo: un modello di <a href="https://arxiv.org/pdf/1211.3711.pdf">trasduzione di sequenza</a> di <a href="https://en.wikipedia.org/wiki/Recurrent_neural_network">reti neurali ricorrenti</a> (RNN) per il riconoscimento vocale (<a href="https://ai.googleblog.com/2019/03/an-all-neural-on-device-speech.html">RNN-T</a>), un modello di reti neurali ricorrenti basato su testo per <a href="https://www.tensorflow.org/tutorials/text/text_generation">punteggiatura non pronunciata</a> e un modello di <a href="https://en.wikipedia.org/wiki/Convolutional_neural_network">reti neurali convoluzionali</a> (CNN) per la <a href="https://ai.google/research/pubs/pub45611">classificazione degli eventi sonori</a>. Live Caption integra il segnale dei tre modelli per creare un'unica traccia di sottotitoli, in cui tag di eventi audio, come <span style="font-size: x-small;">[APPLAUSI]</span> e <span style="font-size: x-small;">[MUSICA]</span>, vengono visualizzati senza interrompere il flusso dei risultati del riconoscimento vocale. I simboli di punteggiatura vengono aggiunti in base a previsioni mentre il testo viene aggiornato in parallelo.<br />
<br />
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"><tbody>
<tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFha7HKAqIhZYdnhJBQOl0j-MLF25k-6zYfrR50XDxpNXe0i87w5wZ3tGPm1gzj1m0HIuMVGwyk2IXFeDMPIvGoMyMKIfR-XAMrfizYnY6-n_iScum-5Bvb_oWMut0yQfoJwCCsZ47HB0_/s1600/image1+-+Edited+%25281%2529.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="486" data-original-width="1600" height="194" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhFha7HKAqIhZYdnhJBQOl0j-MLF25k-6zYfrR50XDxpNXe0i87w5wZ3tGPm1gzj1m0HIuMVGwyk2IXFeDMPIvGoMyMKIfR-XAMrfizYnY6-n_iScum-5Bvb_oWMut0yQfoJwCCsZ47HB0_/s640/image1+-+Edited+%25281%2529.png" width="640" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;">Il suono in entrata viene elaborato attraverso un loop di feedback di Sound Recognition e ASR. Il testo o l'etichetta sonora prodotti vengono formattati e aggiunti al sottotitolo.</td></tr>
</tbody></table>
Per il riconoscimento audio, sfruttiamo il lavoro precedente eseguito per il <a href="https://blog.google/products/android/new-features-make-audio-more-accessible-your-phone/">rilevamento di eventi sonori</a>, usando un modello creato sulla base del set di dati <a href="https://ai.googleblog.com/2017/03/announcing-audioset-dataset-for-audio.html">AudioSet</a>. Il modello di Sound Recognition viene utilizzato non solo per generare etichette di effetti sonori popolari, ma anche per rilevare i momenti del parlato. Il motore di <a href="https://en.wikipedia.org/wiki/Speech_recognition">riconoscimento vocale automatico</a> (ASR) RNN-T funziona solo durante il parlato, al fine di ridurre al minimo l'utilizzo della memoria e della batteria. Ad esempio, quando viene rilevata musica e non è presente parlato nel flusso audio, sullo schermo verrà visualizzata l'etichetta <span style="font-size: x-small;">[MUSICA]</span> e il modello ASR verrà scaricato. Il modello ASR viene caricato nuovamente in memoria solo quando nel flusso audio è di nuovo presente il parlato. <br />
<br />
Affinché Live Caption sia più utile, dovrebbe poter funzionare continuamente per lunghi periodi di tempo. Per fare questo, il modello ASR di Live Caption è <a href="https://arxiv.org/abs/1909.12408">ottimizzato per dispositivi edge</a> utilizzando diverse tecniche, come il pruning delle connessioni neurali, che ha ridotto il consumo di energia al 50% rispetto al modello vocale a dimensioni naturali. Tuttavia, sebbene il modello sia significativamente più efficiente dal punto di vista energetico, continua ad assicurare <a href="https://arxiv.org/pdf/1808.05312.pdf">buone</a> <a href="https://arxiv.org/pdf/1910.11455.pdf">prestazioni</a> in vari casi d'uso, come nell'aggiunta di sottotitoli ai video, nel riconoscimento di frasi brevi e nel parlato durante conversazioni telefoniche a banda stretta, isolando al contempo efficacemente i rumori di fondo.<br />
<br />
Il modello di punteggiatura basato su testo è stato ottimizzato per l'esecuzione continua su dispositivo utilizzando un'architettura più piccola dell'equivalente cloud, quindi è stato quantizzato e serializzato utilizzando il runtime di <a href="https://www.tensorflow.org/lite">TensorFlow Lite</a>. Man mano che viene creato il sottotitolo, i risultati del riconoscimento vocale vengono aggiornati rapidamente diverse volte al secondo. Al fine di risparmiare sulle risorse computazionali e fornire un'esperienza utente fluida, la previsione della punteggiatura viene eseguita sulla parte finale del testo dalla frase riconosciuta più di recente e, se i risultati ASR aggiornati successivi non cambiano tale testo, i risultati a cui è stata aggiunta la punteggiatura in precedenza sono conservati e riutilizzati. <br />
<br />
<h3>
<strong>Uno sguardo al futuro</strong></h3>
Live Caption è ora disponibile in inglese su Pixel 4 e sarà presto disponibile su Pixel 3 e altri dispositivi Android. Non vediamo l'ora di offrire questa funzionalità a un maggior numero di utenti espandendo il supporto ad altre lingue e migliorando ulteriormente la formattazione al fine di migliorare l'accuratezza e la coerenza percepite dei sottotitoli, in particolare per <a href="https://ai.googleblog.com/2019/08/joint-speech-recognition-and-speaker.html">contenuti con più parlanti</a>.<br />
<br />
<h3>
<strong>Ringraziamenti</strong></h3>
<em>Il core team comprende Robert Berry, Anthony Tripaldi, Danielle Cohen, Anna Belozovsky, Yoni Tsafir, Elliott Burford, Justin Lee, Kelsie Van Deman, Nicole Bleuel, Brian Kemler e Benny Schlesinger. Vorremmo ringraziare il team di Google Speech, in particolare Qiao Liang, Arun Narayanan e Rohit Prabhavalkar per il loro approfondito lavoro sul modello ASR e Chung-Cheng Chiu del Google Brain Team; Dan Ellis e Justin Paul per il loro aiuto nell'integrazione del modello Sound Recognition; Tal Remez per il suo aiuto nello sviluppo del modello di punteggiatura; Kevin Rocard ed Eric Laurent per il loro aiuto con l'API di acquisizione audio Android; ed Eugenio Marchiori, Shivanker Goel, Ye Wen, Jay Yoo, Asela Gunawardana e Tom Hume per il loro aiuto nel lavoro sull'infrastruttura Android.</em><!--<meta name="original_url" content="http://ai.googleblog.com/2019/10/on-device-captioning-with-live-caption.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-27457501587874546282019-12-02T08:00:00.000+01:002019-12-02T08:00:02.641+01:00Best practice per organizzare una sessione di programmazione in live streamingPubblicato da <a class="eu ev bi bj bk bl bm bn bo bp ew bs bt ex ey" href="https://medium.com/@yanchenum?source=post_page-----18d28b3a8d93----------------------" rel="noopener" style="-webkit-tap-highlight-color: transparent; border: inherit; box-sizing: inherit; cursor: pointer; fill: inherit; font-family: inherit; font-size: inherit; font-weight: inherit; letter-spacing: inherit; margin: 0px; padding: 0px;">Yan Chen</a><br />
<br />
<div style="text-align: center;">
<img alt="" height="357" src="https://cdn-images-1.medium.com/max/1024/0*5e8cSvZaG83--mC7" width="640" /></div>
<br />
<br />
<figure><figcaption style="text-align: center;">(credito: <a href="https://www.youtube.com/watch?v=YYP5lqgno4k">https://www.youtube.com/watch?v=YYP5lqgno4k</a>)</figcaption></figure><br />
Il live streaming è una pratica sempre più diffusa per la condivisione delle conoscenze nelle community di sviluppatori, grazie alla quale gli sviluppatori trasmettono il loro lavoro in diretta su piattaforme di streaming come YouTube. Come stagista estivo nel team Flutter di Google, ho condotto uno studio basato su interviste per capire perché e come gli sviluppatori condividono le loro conoscenze di programmazione tramite il live streaming. In questo articolo, desidero condividere alcune delle best practice che ho individuato per tenere una sessione di programmazione in live streaming, in modo che <em>tu</em> possa creare con successo la tua e condividere le tue conoscenze di programmazione con la tua community. Consiglio a tutti di provare il live streaming perché non solo può aiutare gli altri, ma lo streamer può anche ricevere feedback in tempo reale dal proprio pubblico.<br />
<h3>
Interviste a streamer e spettatori</h3>
Ho intervistato 20 persone, 14 streamer e 6 spettatori, che hanno regolarmente partecipato a live streaming di programmazione su YouTube o Twitch. Tutti gli streamer che abbiamo intervistato hanno riferito che condividere le loro conoscenze di programmazione e le loro abilità pratiche era lo scopo principale del live streaming. Inoltre, abbiamo selezionato spettatori che in genere guardano il live streaming per almeno 30 minuti alla volta, per assicurarci di acquisire un'opinione informata sull'argomento.<br />
<br />
<br />
<br />
<figure style="text-align: center;"><img alt="" src="https://cdn-images-1.medium.com/max/290/0*RWD-5EEHxQ1aCCwi" /></figure><br />
Le persone che ho intervistato utilizzano diversi tipi di linguaggi di programmazione tra cui JavaScript (8), Python (4), C# (3), Dart (2), Rust (2) e C (1). Dei 20 intervistati, 14 erano sviluppatori professionisti pagati per sviluppare software, 4 erano studenti e 2 erano programmatori hobbisti. Dei 14 streamer, 7 di loro trasmettevano principalmente streaming su attività di programmazione correlate a progetti open source.<br />
<h3>
9 suggerimenti per una sessione di live streaming sulla programmazione</h3>
Parlando con streamer esperti e spettatori nella community degli sviluppatori, ho imparato molte best practice da seguire e insidie da evitare. Desidero condividere con te 9 suggerimenti, suddivisi in tre sezioni: prima del live streaming, durante il live streaming e dopo il live streaming.<br />
<h3>
<strong><em>Prima del live streaming</em></strong></h3>
<h4>
1. Trova un argomento di interesse per la tua community</h4>
Alcuni streamer hanno scelto gli argomenti dello streaming in base agli interessi delle loro community. Ad esempio, partendo da conversazioni sui canali Discord o Slack, commenti ai loro video precedenti o risultati di sondaggi sugli streaming precedenti. A seconda di quanto ti senti a tuo agio nel farlo, puoi chiedere in modo proattivo agli utenti a quali argomenti sono interessati e invitarli a guardare il tuo stream.<br />
<h4>
2. Fai diversi annunci la settimana precedente</h4>
La maggior parte degli streamer mantiene un orario di streaming regolare (ad esempio, domenica 10:00-12:00); questo è consigliato se desideri che gli spettatori seguano la tua sessione ogni settimana. Tuttavia, se non hai un orario di streaming regolare o desideri modificarlo in una settimana specifica, assicurati di ricordare la nuova data e ora più volte agli spettatori (ad esempio, 5 giorni, 2 giorni e il giorno prima della sessione).<br />
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/593/0*WBnCrRnxqRMnFYdf" /></figure><br />
<h4>
3. Proteggi la tua privacy</h4>
Tutti gli streamer sono preoccupati della loro privacy. Hanno timore di condividere per sbaglio informazioni personali o informazioni aziendali della loro organizzazione. Ecco un elenco di pratiche seguite dagli streamer esperti per proteggere la loro privacy:<br />
<ul>
<li>Utilizza la modalità di navigazione in incognito e nascondi i preferiti</li>
</ul>
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/948/1*BxmLRsMw0ZSPWXLF0JTtDQ.png" /></figure><br />
<ul>
<li>Condividi solo la parte pertinente dello schermo</li>
<li>Prima dello streaming, accedi a tutti gli account che utilizzerai nel corso della sessione (ad esempio, GitHub, Discord), in modo da non mostrare accidentalmente il tuo nome utente/password.</li>
<li>Disattiva le notifiche (come e-mail e messenger)</li>
<li>Non rivolgere la videocamera verso qualcosa che sia pubblicamente riconoscibile (come edifici con una forma distintiva)</li>
</ul>
<h4>
4. Crea un elenco di domande frequenti e risorse</h4>
Alcuni spettatori si collegheranno a sessione già iniziata e potrebbero non riuscire a comprendere ciò a cui stai lavorando. Invece di distrarti nel rispondere alle domande, prepara un elenco di domande che prevedi possano essere poste dal pubblico. Ad esempio:<br />
<em>D: Di cosa tratta questo streaming?</em><br />
<em>R: Stiamo creando un'app Hacker News Reader in Flutter!</em><br />
<em>D: Dov'è il repository GitHub?</em><br />
<em>R: </em><a href="https://goo.gle/2MXeNeR"><em>https://goo.gle/2MXeNeR</em></a><br />
<em>D: Quale IDE stai utilizzando nello streaming?</em><br />
<em>R: IntelliJ.</em><br />
<h4>
5. Prepara un piano generale</h4>
Sebbene il lavoro di preparazione per il live streaming sia di gran lunga minore rispetto a quello necessario per la registrazione di un video, è sempre consigliabile preparare un piano generale. Ad esempio, potresti scrivere i passaggi di ciò che desideri realizzare, in modo da rimanere sempre concentrato.<br />
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*r3sTKix-QiZV6vrB" /><figcaption style="text-align: center;">(credito: <a href="https://unsplash.com/photos/RLw-UC03Gwc">https://unsplash.com/photos/RLw-UC03Gwc</a>)</figcaption></figure><br />
<h4>
6. Non è necessario completare prima il lavoro</h4>
<blockquote>
<em>"Non si tratta di me che cerco di risolvere un problema. Sono io che cerco di imparare qualcosa di nuovo o che osservo qualcun altro mentre scrive codice." - Uno spettatore</em></blockquote>
Numerosi spettatori hanno riferito che quando decidono di guardare il live streaming non hanno problemi specifici da risolvere o obiettivi di apprendimento concreti. Ciò significa che non devi necessariamente preparare tutto in anticipo. Agli spettatori piace vedere in quali tipi di problemi ti imbatterai e come li risolverai. Ad esempio, ecco cosa ha detto uno spettatore nel nostro studio:<br />
<blockquote>
<em>"Mi piace osservare le varie fasi del ragionamento del programmatore e il fatto che commetta errori. Molte persone apportano troppe modifiche e quindi finisci per ritrovarti solo un programma fluido e senza errori. Non cercano né consultano nulla e per me non è realistico. Quindi penso che sia più divertente e più facile seguire molti video in live streaming o i relativi arcade video, in cui sono ancora presenti gli errori." - Uno spettatore</em></blockquote>
Numerosi spettatori hanno riferito che quando decidono di guardare il live streaming non hanno problemi specifici da risolvere o obiettivi di apprendimento concreti. Ciò significa che non devi necessariamente preparare tutto in anticipo. Agli spettatori piace vedere in quali tipi di problemi ti imbatterai e come li risolverai.<br />
<h3>
<strong><em>Durante lo streaming</em></strong></h3>
Fantastico! Hai completato la preparazione e ora sei in onda! Gli spettatori guardano i live streaming perché vogliono comprendere come pensa lo streamer, il suo approccio al debug e perché sceglie una strategia rispetto a un'altra. Questo ci porta al prossimo suggerimento:<br />
<h4>
<strong>7. Coinvolgi i tuoi spettatori</strong></h4>
Esistono due tecniche per coinvolgere gli spettatori.<br />
La prima è esplicitare i tuoi pensieri<em> : </em>puoi chiedere agli spettatori di ricordarti di farlo se ti risulta difficile.<br />
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*h4OqTkRAx1_-RQiw" /><figcaption style="text-align: center;">(credito: <a href="https://unsplash.com/photos/ASKeuOZqhYU">https://unsplash.com/photos/ASKeuOZqhYU</a>)</figcaption></figure><br />
<blockquote>
<em>"Faccio domande su cose che non conosco o quando potrei implementare una cosa oppure un'altra." - Uno streamer</em></blockquote>
La seconda tecnica consiste nel chiedere agli spettatori di fornire degli input. Ad esempio, potresti tenere una breve sessione di domande e risposte o chiedere loro di suggerirti cosa fare per la prossima sessione mediante un sondaggio. Puoi anche chiedere aiuto ai tuoi spettatori se rimani bloccato mentre programmi. Non devi necessariamente sapere tutto e loro vogliono vederti raggiungere il tuo obiettivo!<br />
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*1Qz7x7ZMo0Ar75hc" /><figcaption style="text-align: center;">(credito: <a href="https://unsplash.com/photos/YLUvemTiRtk">https://unsplash.com/photos/YLUvemTiRtk</a>)</figcaption></figure><br />
<h4>
<strong>8. Moderazione della chat</strong></h4>
Quando il tuo pubblico diventerà numeroso, chiedi ad alcuni spettatori affidabili di aiutarti a moderare la chat in modo da poterti concentrare sul codice. Per far crescere una community sana, assicurati di affrontare problemi come molestie, spam e troll non appena si verificano.<br />
<h3>
<strong><em>Dopo lo streaming</em></strong></h3>
Congratulazioni! Hai tenuto una sessione di live streaming di successo. Ora puoi caricare il tuo video su YouTube per condividerlo con un pubblico più ampio. Questo ci porta all'ultimo suggerimento:<br />
<h4>
<strong>9. Se hai tempo, crea un "timetable"</strong></h4>
Poiché la registrazione di un live streaming è spesso lunga, gli utenti apprezzano la possibilità di avere una tabella di timestamp per passare da un argomento all'altro. Il Flutter Boring Show fornisce un buon esempio di tale tabella.<br />
<br />
<br />
<br />
<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*KQvECPhOz7KPP1k2" /><figcaption style="text-align: center;">(link: <a href="https://youtu.be/SJKrtx759Xk)">https://youtu.be/SJKrtx759Xk)</a></figcaption></figure><br />
<h3>
Pronto per lo streaming?</h3>
Sei pronto per organizzare un fantastico live streaming su Flutter o qualsiasi altro strumento di programmazione che desideri condividere? Spero che i miei suggerimenti ti possano tornare utili!<br />
<!--<meta name="original_url" content="https://medium.com/flutter/best-practices-for-hosting-a-live-streaming-coding-session-18d28b3a8d93">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-3914651406692547642019-11-29T08:00:00.000+01:002019-11-29T08:00:06.929+01:00Lasciamo giocare i bambini: un giovane oratore del DevFest e un organizzatore di DevFest parlano di tecnologia<div style="text-align: center;">
<img alt="Banner DevFest" border="0" data-original-height="396" data-original-width="1600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJxMOqyqVJDi1JmJr6pe727373mX72ScSz-RkYoSfc41JCbiXlQmQ1RkxqAKgmJLyFgbtYdHaIEe7fONrcdX8DE2DIfIHZ6fPw6uYGYY2Kv8VNDOr5YgwANgbpBySotyyk7oSp-S1QhWg/s1600/devfest-header-gdg.png" style="width: 100%;" title="" />
</div>
Mentre continuano a svolgersi in tutto il mondo oltre 400 eventi <a href="https://devfest.withgoogle.com/">DevFest</a> organizzati dalle community, un aspetto sta diventando sempre più chiaro: i bambini stanno assumendo il controllo. Non stiamo scherzando. Molti giovani studenti stanno salendo sul palco in questa stagione per parlare di argomenti che vanno dal machine learning alla robotica... e le persone li adorano.<br />
<div>
<br /></div>
<div>
<div>
E c'è di più... questi bambini e gli organizzatori della community <a href="https://developers.google.com/community/gdg">GDG</a> (Google Developers Groups) dei DevFest locali stanno diventando grandi amici. Lo abbiamo visto di recente a un DevFest a San Francisco, dove Vikram Tiwari, un GDG Lead, e l'undicenne Aaron Ma, il più giovane speaker dell'evento, hanno avuto un'interessante conversazione sulla programmazione. </div>
</div>
<div>
<br /></div>
<div>
Volevamo coinvolgerti nella loro conversazione, quindi abbiamo chiesto a Vikram di rispondere ad alcune domande sulla scrittura di codice e ad Aaron di ribattere alle sue risposte. Dai un'occhiata alla loro conversazione qui sotto! </div>
<div>
<br /></div>
<div>
<h3>
Qual è il tuo linguaggio di programmazione preferito? </h3>
</div>
<div>
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1q_-5_IgLpf31y-29RxPCWvNKzpchuwYqg_ZH9Tv5ds5PVJjU6P1weUHu-xMSyk6orBm3R4kwtUjDVAGy706smVYDs8VB2UkqLPgIWqH-O7SlXyL_zZPCOQpM4Mh09_PnanYWU31C1aQ/s1600/Vikram.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="200" data-original-width="200" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh1q_-5_IgLpf31y-29RxPCWvNKzpchuwYqg_ZH9Tv5ds5PVJjU6P1weUHu-xMSyk6orBm3R4kwtUjDVAGy706smVYDs8VB2UkqLPgIWqH-O7SlXyL_zZPCOQpM4Mh09_PnanYWU31C1aQ/s200/Vikram.jpeg" width="200" /></a>
<br />
<div>
<div>
<b><br /></b></div>
<div>
<b>Vikram: </b>Direi JavaScript: era il linguaggio che non interessava a nessuno e poi improvvisamente node.js ha cambiato l'intero panorama. Al giorno d'oggi, non puoi sfuggire a js, è ovunque, dai browser all'IoT e ora persino nel machine learning. La parte migliore dell'uso di js è la flessibilità che ti offre. Ad esempio, è facile commettere errori in js, ma poi se vuoi prototipare rapidamente, non ti mette i bastoni tra le ruote. E, naturalmente, non si può certo dimenticare il vivace ecosistema node.js, che punta sempre a facilità d'uso e velocità. </div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1W3upDTZMg4FD5W4bHqHZe_BGZOj0QJkJIJJlDrnioN5DhVDFx5Q9C9Fiqo6tdrZctOxm54DPwKpqm2VogKnG8McKaMPMetPHyOAut5aFPKe_iINBtcvlAJPPjaw-R5XELLmouDuQ3Ko/s1600/Screen+Shot+2019-11-15+at+4.41.43+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Aaron Ma, 11 anni" border="0" data-original-height="1072" data-original-width="1072" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1W3upDTZMg4FD5W4bHqHZe_BGZOj0QJkJIJJlDrnioN5DhVDFx5Q9C9Fiqo6tdrZctOxm54DPwKpqm2VogKnG8McKaMPMetPHyOAut5aFPKe_iINBtcvlAJPPjaw-R5XELLmouDuQ3Ko/s200/Screen+Shot+2019-11-15+at+4.41.43+PM.png" title="" width="200" /></a>
<br />
<div>
<br /></div>
<div>
<b>Aaron: </b>Andiamo, Vikram! JavaScript è interessante, ma c'è molto di meglio. Come Python... è chiaramente superiore! Il linguaggio è TALMENTE facile da usare, potente, versatile, ha un'eccellente leggibilità e funziona ovunque. Dimmi, cosa c'è che non piace!? Personalmente, adoro l'usabilità di Python, il che significa che puoi usarlo ovunque, dai siti Web al machine learning.</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br />
<br />
<h3>
Usi qualche segreto speciale quando programmi? </h3>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh73LefVN1aVHJt9vALMRauEQikp9H4Q12pu3J4T_cAtc34O83neUSGqyON4TE0DVocyL5YhDRo7I-21eBWGfXBDyTTG0wO7U_HAXEEf87dZPENxkNKHkumQSWee_NvjI6edtmyeDYq1CU/s1600/Vikram.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em; text-align: left;"><img border="0" data-original-height="200" data-original-width="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh73LefVN1aVHJt9vALMRauEQikp9H4Q12pu3J4T_cAtc34O83neUSGqyON4TE0DVocyL5YhDRo7I-21eBWGfXBDyTTG0wO7U_HAXEEf87dZPENxkNKHkumQSWee_NvjI6edtmyeDYq1CU/s1600/Vikram.jpeg" /></a></div>
<div>
<b><br /></b> <b>Vikram:</b> Ho due "segreti" preferiti. Il primo è commentare quanto più codice possibile per isolare il problema a una parte specifica della base di codice. L'altro è chiedere sempre aiuto. Generalmente, bisogna creare un esempio di codice proof-or-error autonomo e inviarlo su GitHub o Stack Overflow. In questo modo, imparo non solo dov'era l'errore nel mio codice, ma anche cosa fosse sbagliato nel mio ragionamento sul codice/sulla logica.</div>
<div>
<br /></div>
<h3>
</h3>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvz_X-Xj3PdIv3IlP_MtLbsKpKiwqbqfqbjD8L7raJgCnYxztDj3Igub5e0IDeSxGvdj65zKcjCvT69BsnLPiSaTrA2CnSN_jkfIh32AK8WTFfykG-PGxvGdNJXMq4bx5f-1TK2HusBwc/s1600/Screen+Shot+2019-11-15+at+4.41.43+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><b><img border="0" data-original-height="1072" data-original-width="1072" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvz_X-Xj3PdIv3IlP_MtLbsKpKiwqbqfqbjD8L7raJgCnYxztDj3Igub5e0IDeSxGvdj65zKcjCvT69BsnLPiSaTrA2CnSN_jkfIh32AK8WTFfykG-PGxvGdNJXMq4bx5f-1TK2HusBwc/s200/Screen+Shot+2019-11-15+at+4.41.43+PM.png" width="200" /></b></a></div>
<div>
<b><br /></b> <b>Aaron: </b>Io ho due "segreti". Per me la leggibilità è TUTTO. Il primo segreto è che mi piace formattare il codice il più possibile, in modo che gli altri partecipanti al mio progetto open source possono leggere la mia base di codice facilmente. Inoltre, se vuoi diventare un vero maestro del debug, devi commentare le funzioni non necessarie per accelerare il tempo di output. Questo ti renderà molto più veloce. </div>
<div>
<br /></div>
<div>
<br />
<br />
<br />
<h3>
<b><span style="color: white; font-size: large;">In che modo fai pratica e aumenti le tue abilità?</span></b></h3>
<h3>
In che modo fai pratica e aumenti le tue abilità?</h3>
<h3>
</h3>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMhg5ndcGWTnksAYGrR1mgJadTs7lPj0-cDYC6P94kEMBgj_lU5DvuM1cqRvMAlHUMN896Od-_A0qEesECL8lRoryj7Idq0dPPVtWNkmgDu3vCS2fMxv6DGhmqcBFXJr3A29zNufVMJF8/s1600/Vikram.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em; text-align: justify;"><img border="0" data-original-height="200" data-original-width="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMhg5ndcGWTnksAYGrR1mgJadTs7lPj0-cDYC6P94kEMBgj_lU5DvuM1cqRvMAlHUMN896Od-_A0qEesECL8lRoryj7Idq0dPPVtWNkmgDu3vCS2fMxv6DGhmqcBFXJr3A29zNufVMJF8/s1600/Vikram.jpeg" /></a></div>
<b> Vikram:</b><span style="font-weight: normal;"> Mi piace lavorare su progetti open source non miei. Questo mi aiuta a crescere non solo come sviluppatore core, ma anche come comunicatore. Spesso ci sono concetti e scelte di design che sono comuni in altri linguaggi, ma che non ti vengono in mente naturalmente se lavori frequentemente in un solo linguaggio. Con l'open source, riesco a lavorare con diversi linguaggi e imparo cosa fare dai migliori, e a volte cosa non fare da... beh... da coloro che non sono i migliori. </span><br />
<h3>
</h3>
<h3>
</h3>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvz_X-Xj3PdIv3IlP_MtLbsKpKiwqbqfqbjD8L7raJgCnYxztDj3Igub5e0IDeSxGvdj65zKcjCvT69BsnLPiSaTrA2CnSN_jkfIh32AK8WTFfykG-PGxvGdNJXMq4bx5f-1TK2HusBwc/s1600/Screen+Shot+2019-11-15+at+4.41.43+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="1072" data-original-width="1072" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgvz_X-Xj3PdIv3IlP_MtLbsKpKiwqbqfqbjD8L7raJgCnYxztDj3Igub5e0IDeSxGvdj65zKcjCvT69BsnLPiSaTrA2CnSN_jkfIh32AK8WTFfykG-PGxvGdNJXMq4bx5f-1TK2HusBwc/s200/Screen+Shot+2019-11-15+at+4.41.43+PM.png" width="200" /></a></div>
<div>
<div>
<b><br /></b> <b>Aaron:</b> Sicuramente l'open source! In particolare le competizioni open source, perché sono super eccitanti, ti fanno vedere dove devi migliorare e ti consentono di verificare se sei davvero preparato in un determinato campo di studio. Mi piace anche contribuire o creare miei progetti open source in modo da poter crescere come sviluppatore con una mentalità open source. In questo momento, sono il più giovane collaboratore di TensorFlow di Google, quindi faccio un appello a tutti i ragazzi là fuori che stanno leggendo: unitevi a me!</div>
</div>
<h3>
</h3>
<h3>
</h3>
<h3>
</h3>
<div>
<div>
<h3>
</h3>
<h3>
Ti piace passare direttamente a scrivere codice o ragioni su ogni riga prima di scrivere?</h3>
</div>
</div>
<div>
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp_ih635fYlryM_UhYRYcrU_aL3leV9qXGJVfJi7T4ePEfbN-Tyh-aE1sig_BqFc0gpqqpfoI6oeNMPt6diJa1hJzRM5JqTIVfYpPvfTpi457eEMCk04mFWCB-iax0myJ8qj-O-WsHryI/s1600/Vikram.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Vikram Tiwari, GDG lead " border="0" data-original-height="200" data-original-width="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgp_ih635fYlryM_UhYRYcrU_aL3leV9qXGJVfJi7T4ePEfbN-Tyh-aE1sig_BqFc0gpqqpfoI6oeNMPt6diJa1hJzRM5JqTIVfYpPvfTpi457eEMCk04mFWCB-iax0myJ8qj-O-WsHryI/s1600/Vikram.jpeg" title="" /></a>
<br />
<div>
<div>
<b>Vikram:</b> Mi piace pensare in anticipo al problema. Tuttavia, se il problema è già stato analizzato, passo subito all'esecuzione. In questo caso, in genere comincio con la scrittura di alcune pseudo funzioni, simulandone gli input e gli output, collegandoli insieme e infine scrivendo la logica effettiva. Questo approccio generalmente mi aiuta a cambiare contesto, nel senso che posso smettere di lavorare su quel problema specifico in qualsiasi momento e riprenderlo dallo stesso punto in un secondo momento.</div>
</div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpXuLqnMiWr1b2sMJmJikY2nKxQEbj9RjHxb7RwN4Cp-pl1ZR-R0oXREPGi7kBQtS7S5TvWObrIhQrX1f8ywfgCBypcmXYu3GCq10rgs5C3qUQftn_Tijq-zFyHB1jsyNcXXVltpXp4vA/s1600/Screen+Shot+2019-11-15+at+4.41.43+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Aaron Ma, 11 anni" border="0" data-original-height="1072" data-original-width="1072" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhpXuLqnMiWr1b2sMJmJikY2nKxQEbj9RjHxb7RwN4Cp-pl1ZR-R0oXREPGi7kBQtS7S5TvWObrIhQrX1f8ywfgCBypcmXYu3GCq10rgs5C3qUQftn_Tijq-zFyHB1jsyNcXXVltpXp4vA/s200/Screen+Shot+2019-11-15+at+4.41.43+PM.png" title="" width="200" /></a>
<br />
<b><br /></b> <b>Aaron:</b> Mi piace il tuo approccio! Se qualcuno ha già implementato il problema e lo ha "impacchettato", proverei ad andare direttamente al processo di distribuzione. Ma se nessuno ha implementato il problema, per prima cosa inizierei a scrivere pseudocodice, quindi convertirei lentamente lo pseudocodice in codice effettivo funzionante.<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<br />
<h3>
Qual è l'aspetto che preferisci della community DevFest?</h3>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQv55cyJjeopY_pMrLaYFr-SP6iAMVEoMBlH81Rb3KKXZX9SkxhdViP5gmX6XaDXnPT7G9CLIaPWe61b7Sq1tGfS0u5ugzcKbZsvpBTKmalqvdD491c2BR9UG-q8e18Ys3kyIkamLawaI/s1600/Vikram.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Vikram Tiwari, GDG lead " border="0" data-original-height="200" data-original-width="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQv55cyJjeopY_pMrLaYFr-SP6iAMVEoMBlH81Rb3KKXZX9SkxhdViP5gmX6XaDXnPT7G9CLIaPWe61b7Sq1tGfS0u5ugzcKbZsvpBTKmalqvdD491c2BR9UG-q8e18Ys3kyIkamLawaI/s1600/Vikram.jpeg" title="" /></a></div>
<br />
<b>Vikram: </b>DevFest è la casa di tutti gli sviluppatori, di ogni estrazione sociale, con idee di ogni genere. Sì, questa famiglia ama sviluppare le tue competenze tecniche, ma si impegna anche ad aiutarti a superare qualsiasi barriera sociale che potresti incontrare. Questa community ti aiuta in tutto e per tutto, facendoti sentire più a tuo agio con le persone e più sicuro nello scrivere codice.<br />
<br />
<br />
<br />
<br />
<br />
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMyAaZ9fDGhpgB63VgC9_o_n32Bu5_XwG-KStaVB3bbSApSZFjXS6hCVC8hw9LuFaeTWmIPeZi_vHYDvvq_9RI6w-DSSGD6-9eQEEXYJWKYvtF8CIipxd8qHpIhmjZx4W3Gwd-nC5D8ho/s1600/Screen+Shot+2019-11-15+at+4.41.43+PM.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img alt="Aaron Ma, 11 anni" border="0" data-original-height="1072" data-original-width="1072" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMyAaZ9fDGhpgB63VgC9_o_n32Bu5_XwG-KStaVB3bbSApSZFjXS6hCVC8hw9LuFaeTWmIPeZi_vHYDvvq_9RI6w-DSSGD6-9eQEEXYJWKYvtF8CIipxd8qHpIhmjZx4W3Gwd-nC5D8ho/s200/Screen+Shot+2019-11-15+at+4.41.43+PM.png" title="" width="200" /></a></div>
<b>Aaron: </b>Siamo una DevFamily! ❤️Non potrei essere più d'accordo. L'aspetto che preferisco di DevFest è come questa community possa essere una grande fonte d'ispirazione. Come sviluppatori DevFest, abbiamo la possibilità di cambiare il modo in cui tutti pensiamo a CS ogni volta che ci riuniamo. Dagli studenti come me agli esperti di lunga data, qui c'è uno scambio di idee così aperto e positivo che è davvero entusiasmante e mi rende sempre felice. <br />
<div>
<br /></div>
<div>
<br /></div>
<div>
<br /></div>
<div>
<div>
<em><br /></em>
<em><br /></em>
<em>Vuoi partecipare a una conversazione come questa? Rispondi a queste domande con #DevFest o trova un DevFest vicino a te su devfest.withgoogle.com.</em></div>
</div>
<div>
<br /></div>
<!--<meta name="original_url" content="http://developers.googleblog.com/2019/11/young-devfest-speaker-and-organizer-talk-tech.html">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0tag:blogger.com,1999:blog-4524276413957698342.post-55112805969697113152019-11-25T08:00:00.000+01:002019-11-25T08:00:09.571+01:00Creare ed eseguire il deployment di modelli TensorFlow.js con AutoML<em>Pubblicato da Daniel Smilkov, Sandeep Gupta e Vishy Tirumalashetty</em><br />
<a href="http://tensorflow.org/js">TensorFlow.js</a> è una libreria open source che consente di definire, addestrare ed eseguire modelli di machine learning in JavaScript. Questa libreria ha permesso agli sviluppatori dell'ampia community JavaScript di creare ed eseguire il deployment di modelli di machine learning, rendendo possibili nuove classi di calcolo su dispositivo. TensorFlow.js è eseguito in tutti i principali browser, lato server in Node.js e recentemente anche in <a href="https://github.com/tensorflow/tfjs-wechat">WeChat</a> e <a href="https://github.com/tensorflow/tfjs/tree/master/tfjs-react-native">React Native</a>, fornendo alle app ibride accesso a ML senza dover uscire dall'ecosistema JS. Siamo entusiasti di presentare un nuovo modo per gli sviluppatori JavaScript di addestrare in tutta facilità un modello personalizzato per i propri dati ed eseguirne il deployment nell'applicazione JavaScript mediante il servizio AutoML di GCP.<br />
Uno degli obiettivi principali che ci proponiamo di raggiungere con TensorFlow.js è quello di consentire agli sviluppatori JS di avvalersi dei vantaggi di ML senza dover creare i propri modelli. Esistono due modi per applicare il potere di ML alle tue applicazioni JavaScript: usare uno dei nostri modelli preconfezionati o affinare un modello sulla base dei tuoi dati.<br />
Ad esempio, i nostri modelli preconfezionati <a href="https://medium.com/tensorflow/real-time-human-pose-estimation-in-the-browser-with-tensorflow-js-7dd0bc881cd5">Pose estimation</a> e <a href="https://medium.com/tensorflow/introducing-bodypix-real-time-person-segmentation-in-the-browser-with-tensorflow-js-f1948126c2a0">Body segmentation</a> consentono di creare <a href="https://twitter.com/teropa/status/1001151524351959041">nuove forme di interazione utente</a>, andando a costituire la base di nuovi <a href="https://experiments.withgoogle.com/collection/creatability">strumenti di accessibilità</a>. Tutti questi modelli sono pubblicati su NPM, puoi usarli con poche righe di codice (non è necessaria alcuna conoscenza di ML!):<br />
<pre style="overflow-wrap: break-word; white-space: pre-wrap;"><script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/posenet"></script>
<img id="tennis" src="tennis.jpg"/>
<script>
async function run() {
const net = await posenet.load();
const image = document.getElementById('tennis');
const pose = await net.estimateSinglePose(image);
console.log(pose);
}
run();
</script></pre>
<iframe frameborder="0" height="0" scrolling="no" src="" width="0"><a href="https://medium.com/media/59ef70f67a812addee794523ec1faa84/href">https://medium.com/media/59ef70f67a812addee794523ec1faa84/href</a></iframe><br />
Se disponi di dati, puoi iniziare con un modello pre-addestrato e affinarlo. I modelli pre-addestrati e l'addestramento stesso sono compatibili con Python e JavaScript. Se l'addestramento viene eseguito in Python, puoi convertire facilmente il modello SavedModel o Keras in TensorFlow.js con il nostro <a href="https://github.com/tensorflow/tfjs/tree/master/tfjs-converter#getting-started">convertitore</a>. Se il modello è già in TensorFlow.js, non è necessaria alcuna conversione. <a href="https://codelabs.developers.google.com/codelabs/tensorflowjs-teachablemachine-codelab/index.html#0">Questo codelab</a> spiega come prendere MobileNet, un modello di classificazione di immagini ottimizzato per dispositivi edge, e affinarlo sulla base del tuo set di dati dell'immagine, il tutto in JavaScript.<br />
<h3>
<strong>TensorFlow.js + AutoML</strong></h3>
Siamo entusiasti di annunciare l'integrazione con <a href="https://cloud.google.com/vision/automl/docs/">Cloud AutoML Vision</a>, un servizio cloud che consente agli sviluppatori di addestrare un modello personalizzato sulla base dei propri dati etichettati. Se il tuo caso d'uso è correlato alla classificazione di immagini o al rilevamento di oggetti, puoi usare l'interfaccia utente per caricare i tuoi dati, addestrare un modello edge ed esportarlo direttamente in un modello TensorFlow.js senza alcuna programmazione. I modelli personalizzati possono essere addestrati direttamente con la libreria TensorFlow.js open source (o con Python TensorFlow), ma AutoML offre un servizio intuitivo che automatizza questo processo per te.<br />
<br />
<br />
<figure><img alt="Modello TensorFlow.js" height="404" src="https://cdn-images-1.medium.com/max/1024/0*NyEo0SUJOJKE26c6" width="640" /></figure><br />
Per semplificare il deployment e l'esecuzione efficace dei modelli in TensorFlow.js, abbiamo pubblicato la libreria <a href="https://www.npmjs.com/package/@tensorflow/tfjs-automl">@tensorflow/tfjs-automl</a> su NPM. Dopo aver esportato il modello, puoi seguire le nostre guide dettagliate per la <a href="https://cloud.google.com/vision/automl/docs/tensorflow-js-tutorial">classificazione di immagini</a> e il <a href="https://cloud.google.com/vision/automl/object-detection/docs/tensorflow-js-tutorial">rilevamento di oggetti</a>. Queste guide fanno riferimento alla libreria NPM, illustrando come caricare nel browser il modello pre-addestrato e come effettuare una previsione su un'immagine.<br />
Se già disponi di un modello personalizzato, AutoML può ancora essere uno strumento incredibilmente utile. I modelli AutoML Vision Edge sono ottimizzati per un footprint della memoria ridotto e offrono una bassa latenza, senza dover rinunciare a un'accuratezza elevata. Abbiamo collaborato con numerosi clienti e partner, ottenendo fin da subito risultati e feedback incredibilmente positivi. <a href="https://www.cvpcorp.com/">CVP</a>, una società di consulenza informatica e commerciale, ha condotto una valutazione di alcuni scenari di visione per contribuire al miglioramento della sicurezza nell'ambiente lavorativo nei modelli basati su edge nelle località remote. Di seguito riportiamo quanto affermato da Cal Zemelman, Director of Data science presso CVP, sui risultati ottenuti:<br />
<em>"Stiamo lavorando a un'app per smartphone per un'agenzia federale che esegue la classificazione delle immagini per contribuire a prevenire incidenti e a migliorare la sicurezza pubblica. L'app è scritta principalmente in JavaScript come applicazione web progressiva per un utilizzo multipiattaforma, quindi abbiamo addestrato un modello Keras e lo abbiamo successivamente convertito in TensorFlow.js. Grazie alla nuova funzione 'Esporta in TensorFlow.js', siamo stati in grado di svolgere test usando AutoML per semplificare in modo significativo il nostro flusso di lavoro per la creazione di modelli. In passato, il nostro miglior modello era un ResNet50, riaddestrato che ha raggiunto un'accuratezza del 91%. Il modello di prestazioni bilanciato ottenuto a metà processo dalla classificazione di immagini AutoML ha raggiunto un'accuratezza pari a circa il 99% in 5 ore nodo. Inoltre, le sue dimensioni corrispondono a 1/5 di quelle del modello precedente e la velocità di inferenza è migliorata del 60%".</em><br />
Siamo molto entusiasti dei primi risultati che possiamo mostrare ai nostri clienti e partner e non vediamo l'ora di ricevere nuovi feedback con questa release.<br />
Puoi iniziare subito ad addestrare un modello AutoML Vision Edge. Una volta terminato l'addestramento, puoi esportare il modello TensorFlow.js nella tua applicazione lato client. Con AutoML Vision Edge, paghi solo per eseguire l'addestramento per gli usi che superano le 15 ore nodo ottenute gratuitamente. Non sono previsti costi per l'esportazione o le previsioni lato client.<br />
<h3>
<strong>Passi successivi</strong></h3>
<ul>
<li>Per scoprire di più su AutoML, <a href="https://cloud.google.com/automl/">fai clic qui</a>.</li>
<li>Per il rilevamento di oggetti, segui le guide dettagliate <a href="https://cloud.google.com/vision/automl/object-detection/docs/edge-quickstart">sull'addestramento</a> e <a href="https://cloud.google.com/vision/automl/object-detection/docs/tensorflow-js-tutorial">il deployment</a> di TensorFlow.js</li>
<li>Per la classificazione di immagini, segui le guide dettagliate <a href="https://cloud.google.com/vision/automl/docs/edge-quickstart">sull'addestramento</a> e <a href="https://cloud.google.com/vision/automl/docs/tensorflow-js-tutorial">il deployment</a> di TensorFlow.js</li>
<li>Scopri di più sulla libreria NPM AutoML nella <a href="https://www.npmjs.com/package/@tensorflow/tfjs-automl">documentazione ufficiale</a>.</li>
</ul>
<!--<meta name="original_url" content="https://medium.com/tensorflow/build-and-deploy-tensorflow-js-models-with-the-power-of-automl-1985b8985083">-->Google Developershttp://www.blogger.com/profile/10253570620394112208noreply@blogger.com0