PyTorch Mobile Il est sorti vers octobre de l'année dernière (2019). Avec Tensolflow Lite, l'apprentissage automatique était possible avec Android iOS, mais finalement pytorch 1.3 a été publié pour les appareils mobiles. C'est le meilleur du côté de l'utilisation du pytorch plutôt que du tensorflow! Comme tensorflow Lite, il peut être utilisé avec Android iOS.
Cliquez ici pour plus de détails Site officiel de PyTorch Mobile: https://pytorch.org/mobile/home/
Depuis le site officiel
Faites le tutoriel présenté sur le site officiel. Écrivez à Kotlin! Classez les images à l'aide du modèle entraîné de resNet. (Inférence uniquement)
github est publié https://github.com/SY-BETA/PyTorchMobile
Comme ça ↓ C'est aussi simple que d'afficher les images à classer, les deux premiers résultats du classement et leurs scores. (Qu'est-ce que Canis lupus?)
Seulement ça
Tout d'abord, créez un nouveau projet dans Android Studio. Créez un dossier d'actifs dans ce projet. (Vous pouvez le faire en cliquant avec le bouton droit sur l'application sur le côté gauche de l'interface utilisateur-> Nouveau-> Dossier-> dossier des actifs) Une fois créé, exécutez le code Python suivant dans la même hiérarchie que le dossier d'application pour ce projet
createModel.py
import torch
import torchvision
#Utiliser le modèle resnet
model = torchvision.models.resnet18(pretrained=True)
#En mode inférence
model.eval()
example = torch.rand(1, 3, 224, 224)
traced_script_module = torch.jit.trace(model, example)
traced_script_module.save("app/src/main/assets/resnet.pt")
S'il peut être exécuté avec succès, un fichier appelé resnet.pt
sera ajouté au dossier des actifs créé précédemment.
Enregistrez les exemples d'images suivants dans le dossier assets et dans le dossier drawable sous le nom ʻimage.jpg`
Ajout de ce qui suit à gradle (à compter du 4 janvier 2020)
dependencies {
implementation 'org.pytorch:pytorch_android:1.3.0'
implementation 'org.pytorch:pytorch_android_torchvision:1.3.0'
}
Créez une mise en page appropriée Mise en page avec seulement 1 image et 6 textes verticalement
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Input"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="230dp"
android:scaleType="fitCenter"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:srcCompat="@drawable/image" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Result"
android:textSize="30sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView" />
<TextView
android:id="@+id/result1Score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="32dp"
android:text="TextView"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/result1Class"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textView2" />
<TextView
android:id="@+id/result1Class"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="40dp"
android:gravity="center"
android:text="TextView"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/result2Score"
app:layout_constraintEnd_toEndOf="@+id/result1Score"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/result1Score"
app:layout_constraintTop_toBottomOf="@+id/result1Score" />
<TextView
android:id="@+id/result2Score"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="24dp"
android:text="TextView"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@+id/result2Class"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/result1Class"
app:layout_constraintVertical_bias="0.94" />
<TextView
android:id="@+id/result2Class"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_marginStart="40dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="40dp"
android:layout_marginBottom="32dp"
android:gravity="center"
android:text="TextView"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/result2Score"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="@+id/result2Score"
app:layout_constraintTop_toBottomOf="@+id/result2Score" />
</androidx.constraintlayout.widget.ConstraintLayout>
Chargez le resnet.pt
créé précédemment
MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
////Fonction pour obtenir le chemin du fichier d'actif
fun assetFilePath(context: Context, assetName: String): String {
val file = File(context.filesDir, assetName)
if (file.exists() && file.length() > 0) {
return file.absolutePath
}
context.assets.open(assetName).use { inputStream ->
FileOutputStream(file).use { outputStream ->
val buffer = ByteArray(4 * 1024)
var read: Int
while (inputStream.read(buffer).also { read = it } != -1) {
outputStream.write(buffer, 0, read)
}
outputStream.flush()
}
return file.absolutePath
}
}
///Charger des modèles et des images
///Charger le modèle sérialisé
val bitmap = BitmapFactory.decodeStream(assets.open("image.jpg "))
val module = Module.load(assetFilePath(this, "resnet.pt"))
}
Notez que le chargement d'images et de modèles à partir du dossier des actifs peut être assez fastidieux.
Entrez une image d'exemple à l'aide du module ajouté aux dépendances et resnet et sortez le résultat
MainActivity.kt
///Convertir en tenseur
val inputTensor = TensorImageUtils.bitmapToFloat32Tensor(
bitmap,
TensorImageUtils.TORCHVISION_NORM_MEAN_RGB, TensorImageUtils.TORCHVISION_NORM_STD_RGB
)
///Inférence et ses conséquences
///Propagation vers l'avant
val outputTensor = module.forward(IValue.from(inputTensor)).toTensor()
val scores = outputTensor.dataAsFloatArray
Extraire le score le plus élevé
MainActivity.kt
///Variable pour stocker le score
var maxScore: Float = 0F
var maxScoreIdx = -1
var maxSecondScore: Float = 0F
var maxSecondScoreIdx = -1
///Prenez les deux premiers avec le score le plus élevé
for (i in scores.indices) {
if (scores[i] > maxScore) {
maxSecondScore = maxScore
maxSecondScoreIdx = maxScoreIdx
maxScore = scores[i]
maxScoreIdx = i
}
}
Le nom de la classe à classer Omis car il est très long (il s'agit d'une classification de classe imageNet 1000) Puisqu'il est publié sur github, veuillez copier le contenu de ʻImageNetClasses.kt`
github Liste des noms de classe (ImageNetClasses.kt)
ImageNetClasses.kt
class ImageNetClasses {
var IMAGENET_CLASSES = arrayOf(
"tench, Tinca tinca",
"goldfish, Carassius auratus",
//~~~~~~~~~~~~~~Abréviation(Veuillez copier depuis github)~~~~~~~~~~~~~~~~//
"toilet tissue, toilet paper, bathroom tissue"
)
}
Récupère le nom de la classe déduit de l'index Enfin, affichez le résultat de l'inférence sur la mise en page
MainActivity.kt
///Obtenez le nom de la classe classifié à partir de l'index
val className = ImageNetClasses().IMAGENET_CLASSES[maxScoreIdx]
val className2 = ImageNetClasses().IMAGENET_CLASSES[maxSecondScoreIdx]
result1Score.text = "score: $maxScore"
result1Class.text = "Résultat de la classification:$className"
result2Score.text = "score:$maxSecondScore"
result2Class.text = "Résultat de la classification:$className2"
Terminé! !! Si vous le construisez, vous devriez obtenir un écran comme le début. Veuillez mettre différentes images et jouer avec elles.
La bibliothèque est pratique. Qu'est-ce qu'une classification d'image est possible avec juste cela? J'ai senti que la conversion en tenseur était un peu bloquée, mais maintenant je peux utiliser pytorch pour Android. En passant, au début, la version de pytorch n'était pas la dernière et j'ai eu une erreur lors du chargement du modèle et je ne pouvais pas du tout le faire, et j'étais assez accro à obtenir le chemin du dossier assets.