[PYTHON] Générez des formes physiquement robustes avec GAN et imprimez avec une imprimante 3D

0. La bonne chose à propos de cet article

1. Vue d'ensemble

--DCGAN (Radford et al., 2016) [^ DCGAN] est utilisé, et les informations de résistance sont ajoutées à la fonction de perte pour générer des nombres de haute résistance.

(L'article est long, mais je pense que vous pouvez le lire immédiatement car il représente environ 3/4 de l'image ou un bonus.)

2. Arrière plan

J'ai récemment eu une imprimante 3D, et quand je me demandais si je pouvais faire quelque chose avec la combinaison ** imprimante 3D x apprentissage en profondeur **, j'ai décidé de l'essayer.

Il semble que la théorie de base de la mécanique des matériaux n'ait pas changé au cours des 100 dernières années, j'ai donc voulu aborder du côté de l'apprentissage en profondeur, qui a un haut degré de liberté.

Vous apprécierez peut-être de lire quel nombre de «0-9» devrait être solide. Il existe un type de numéro extrêmement robuste.

(* Je le fais en lisant le livre sur la mécanique des matériaux (Japan Society of Mechanical Engineers, 2007) [^ JSME], donc je peux dire quelque chose d'approprié. S'il y a une erreur, je la corrigerai. Je n'ai pas pu trouver une étude similaire dans la gamme ci-dessus, mais veuillez me le faire savoir.)

[^ JSME]: Mécanique des matériaux de la série de textes JSME, Société japonaise des ingénieurs en mécanique, 2007.

3. Théorie

Si vous n'êtes pas intéressé, vous pouvez l'ignorer du tout.

3.1 Moment secondaire de la section transversale

En premier lieu, la force du mot brut a plusieurs indicateurs. Je ne sais pas comment les magasins de matériaux utilisent le mot force, mais nous, le grand public, utilisons le mot force de plusieurs manières.

Dureté Morse, dureté Vickers, limite d'élasticité (résistance à la traction), etc ... Parmi eux, la force dominante est le ** moment secondaire de section transversale **, qui n'est déterminé que par la forme de la section transversale sans dépendre du matériau. C'est un facteur de la difficulté du membre à se plier.

Lorsque la force est appliquée, la plupart des choses se plient subtilement à un niveau invisible proportionnellement à la force. Et si vous vous penchez trop, la plupart des choses se briseront et vous ne pourrez plus revenir. Inversement, un membre avec une section transversale plus forte est moins susceptible de se casser.

Par exemple, les journaux ne peuvent rien supporter s'ils sont duveteux, mais le simple fait de les rouler les rend raisonnablement raides. (Bien qu'il existe un facteur qui augmente l'épaisseur du papier)

The Japan Society of Mechanical Engineers, dans [^ JSME] Chapitre 5, p63, «lorsqu'une tige mince reçoit une charge latérale qui provoque une flexion dans un plan comprenant l'axe de la tige de la direction latérale, une telle tige est appelée une poutre. Il est défini comme "."

↑ MNIST [1] 形状をした断面と断面二次モーメントと向きの関係、3Dプリントのイメージ

Si vous fixez les deux côtés de la tige allongée en forme de "2" dans cette image, elle devient une "poutre". A ce moment, pour la direction de la flèche **, le moment de section transversale secondaire pour la force verticale est $ I_x $, et le moment de section transversale secondaire pour la force latérale est $ I_y $ **.

C'est un peu déroutant car l'orientation de $ x $ et $ y $ est transposée sur l'axe de traitement d'image. Wikipedia senior [^ wikipedia] a également dit cela, et c'est probablement la norme.

Ensuite, nous expliquerons comment calculer le moment secondaire de la section transversale.

Le moment secondaire transversal $ I_x $ par rapport à la force de l'axe vertical est

I_x = \int_A y^2 dA \tag{1}

Il peut être calculé avec. Où $ A $ est l'aire de la section transversale et $ y $ est la distance verticale de l'axe neutre (le centre de gravité de la section transversale).

De même, le moment secondaire transversal $ I_y $ par rapport à la force de l'axe horizontal est

I_y = \int_A x^2 dA \tag{2}

Il peut être calculé avec. Où $ x $ représente la distance latérale de l'axe neutre.

Il existe également un indice appelé moment polaire secondaire de la section transversale, qui indique la résistance de la section transversale contre la «torsion».

I_r = I_x + I_y \tag{3}

Peut être calculé comme. Comme c'est beaucoup, je vais présenter cette force à l'expérience. "Twisting" est facile à comprendre si vous imaginez la force de rotation appliquée lors de la compression d'un chiffon.

L'unité de ces trois indicateurs est m ^ 4. En effet, le carré de la différence de distance [m ^ 2] est intégré par l'aire [m ^ 2].

En effet, dans le cas d'une section rectangulaire simple, le moment secondaire de la section transversale est

Vous pouvez voir intuitivement qu'il est proportionnel à.

Alors que se passe-t-il dans ce cas?

Tout d'abord, pour faciliter la compréhension, visualisez le moment secondaire en coupe transversale de l'image avec toutes les valeurs de pixel = 1,0 (valeur maximale).

image \Delta I_x \Delta I_y


I_x=1.000 (MAX)
I_y=1.000 (MAX)

Où $ \ Delta I_x $ est l'effet sur le moment secondaire transversal $ I_x $ par pixel unitaire, et $ \ Delta I_y $ est l'effet sur le moment secondaire transversal $ I_y $ par pixel. En les résumant, vous pouvez obtenir $ I_x $ et $ I_y $.

De plus, cette fois, nous la séparerons de l'unité métrique et définirons ce carré comme moment secondaire transversal maximal de 1,0 $.

Affichons une figure similaire avec quelques données de MNIST.

(Pour les valeurs <0,0 <valeur de pixel <1,0, l'approximation est que la valeur de pixel est proportionnelle à la zone. En d'autres termes, si la valeur du pixel est "0,5", la moitié des pixels n'ont pas de section transversale, et si elle est "0,1", il manque 90%. * Ce sera une approximation différente au moment de l'impression finale. )

image \Delta I_x \Delta I_y


I_x=0.112
I_y=0.093

I_x=0.060 I_y=0.036

"0" est élevé pour $ I_x $ et $ I_y $, mais vous pouvez voir que la force dans la direction verticale est particulièrement forte. Au contraire, "1" est faible pour $ I_x $ et $ I_y $, et il n'y a pratiquement pas de force latérale en particulier.

Lors du calcul du moment secondaire de la section transversale, la force a une influence plus forte lorsque la distance de l'axe neutre augmente, et l'influence diminue lorsque la distance de l'axe neutre augmente. Compte tenu de cela, le fait que la plupart des structures dans le monde sont creuses (le contenu est spongieux) est largement affecté par le moment secondaire de la section transversale.

D'après ce qui précède, les sections transversales typiques à haute résistance tout en supprimant le matériau et le poids correspondent à des formes circulaires / carrées creuses et de type H / I (seule la résistance d'un axe est forte). Cette fois, il n'y a pas de restrictions particulières telles que le poids du matériau, de sorte que la forme la plus résistante est le ** "carré" ** où les valeurs de pixels de l'image sont remplies.

Alors, comment garder la forme des nombres tout en conservant leur force?

3.2 Generative Adversarial Nets (Goodfellow et al., 2014)[2]

Le Generative Adversarial Nets (= GAN) utilise deux modèles de réseaux neuronaux, l'un est un générateur qui produit une distribution proche des données, l'autre est un générateur, ou il est généré pour l'entrée de données. Il se compose d'un discriminateur qui détermine si c'est une chose ou non.

Plus le jugement du discriminateur est précis, plus la méthode de rétropropagation des erreurs modifie les paramètres du générateur, ce qui permet au générateur de produire une distribution plus semblable à des données. D'un autre côté, l'inexactitude du jugement du discriminateur est une sanction du discriminateur lui-même, et les paramètres sont modifiés pour améliorer l'exactitude du jugement.

Ceux-ci proviennent de la formulation [^ GAN] de l'équation (4) de Goodfellow et al.

\min _{G} \max _{D} V(D, G)=\mathbb{E}_{\boldsymbol{x} \sim p_{\text {data }}(\boldsymbol{x})}[\log D(\boldsymbol{x})]+\mathbb{E}_{\boldsymbol{z} \sim p_{\boldsymbol{z}}(\boldsymbol{z})}[\log (1-D(G(\boldsymbol{z})))] \tag{4}

Pour l'expliquer en un mot, si vous appliquez cela aux données d'image des nombres, le côté Générateur procédera à l'apprentissage pour générer une image de type nombre, et si l'apprentissage réussit, il générera même des nombres qui n'existent pas dans l'ensemble de données. est.

De plus, diverses méthodes ont été conçues pour la théorie du GAN et les méthodes d'apprentissage, mais cette fois, elles sont basées sur le classique DCGAN [^ DCGAN]. DCGAN est, en un mot, un article qui applique la méthode de base du GAN à un réseau neuronal convolutif.

3.3 Danmen-GAN

Maintenant que nous avons fini d'expliquer la technologie de base, écrivons la logique pour créer des nombres robustes.

Dans un entraînement GAN normal, la perte sur le générateur est l'équation (5). Cela signifie que le discriminateur reçoit le résultat de la génération du générateur lorsque le bruit est entré, et la perte augmente à la vitesse à laquelle le discriminateur répond correctement.

\mathcal{L}_{G} = \mathbb{E} [\log (1 - D(G(z))] \tag{5}

Cependant, avec cela seul, l'apprentissage se déroulera de sorte que les nombres soient générés aléatoirement, donc la fonction $ S (\ cdot) $ qui calcule le moment secondaire de la section transversale à partir de la forme de la section transversale de l'image d'entrée est incorporée, et l'image de la section transversale générée Créez une nouvelle perte $ \ mathcal {L} _ {S} $ pour que plus le moment secondaire transversal est bas, plus le Générateur sera pénalisé.

\mathcal{L}_{S} = \mathbb{E} \left[\|1 - S(G(z))\|_{2}\right] \tag{6}

De plus, si nous introduisons les axes de x vertical, y horizontal et de torsion r dans $ S (\ cdot) $ et les pondérons avec les paramètres α, β et γ, l'équation (6) devient l'équation (7). Devenir.

\mathcal{L}_{S} = \alpha \cdot\mathbb{E} \left[|1 - S_x(G(z))|_2\right] + \beta \cdot\mathbb{E} \left[|1 - S_y(G(z))|_2\right] + \gamma \cdot\mathbb{E} \left[|1 - S_r(G(z))|_2\right]

Enfin, ajoutez l'équation (7) à la perte du côté générateur du GAN pour créer l'équation (8), et c'est terminé.

\mathcal{L}_{All} = \mathcal{L}_{G} + \mathcal{L}_{S} \tag{8}

En utilisant l'équation (8) comme fonction objectif du générateur, la logique est que le moment quadratique de la section transversale peut être augmenté tout en conservant la forme des nombres dans la section transversale.

4. Analyse des données

L'ensemble de données est MNIST [^ MNIST]. Cette fois, nous n'avons besoin que de la source des données générées, nous n'utiliserons donc que les données d'entraînement.

Tout d'abord, je veux savoir à quel point l'intérieur de l'ensemble de données est fort, je vais donc le calculer.

4.1 Force mondiale

Moment secondaire transversal moyen pour chaque axe de l'ensemble de données entier $ \ mathbb {E} \ left [I_x \ right] $, $ \ mathbb {E} \ left [I_y \ right] $, $ \ mathbb {E} \ left J'ai demandé [I_r \ right] $. Nous avons également calculé les écarts types des moments secondaires transversaux $ \ sigma_ {Ix} $, $ \ sigma_ {Iy} $, $ \ sigma_ {Ir} $ pour chaque statistique.

E[I_x] (\sigma_{Ix}) E[I_y] (\sigma_{Iy}) E[I_r] (\sigma_{Ir})
0.088(0.032) 0.063(0.034) 0.076(0.031)

En regardant ce tableau, j'ai le sentiment que les moments secondaires de la section transversale varient en fonction des données. En outre, on peut voir que la résistance dans la direction verticale est supérieure à celle dans la direction horizontale dans son ensemble.

4.2 Force pour chaque numéro

Ensuite, considérant que la forme est biaisée pour chaque nombre, nous avons résumé les valeurs statistiques du moment secondaire transversal pour chaque nombre. Ceci est représenté par un ensemble de moustaches et de tables. Aucun traitement n'est effectué pour les valeurs anormales.

Number(n) E[I_{xn}] (\sigma_{Ixn}) E[I_{yn}] (\sigma_{Iyn}) $E[I_{rn}] $ (\sigma_{Irn})
0 0.121(0.029) 0.110(0.034) 0.116(0.030)
1 0.052(0.015) 0.020(0.014) 0.036(0.013)
2 0.107(0.031) 0.078(0.027) 0.093(0.027)
3 0.106(0.028) 0.066(0.026) 0.086(0.026)
4 0.064(0.018) 0.063(0.026) 0.064(0.021)
5 0.093(0.031) 0.065(0.024) 0.079(0.026)
6 0.083(0.022) 0.065(0.028) 0.074(0.024)
7 0.079(0.021) 0.053(0.022) 0.066(0.020)
8 0.105(0.027) 0.067(0.027) 0.086(0.026)
9 0.074(0.019) 0.054(0.024) 0.064(0.021)

De ceux-ci, nous pouvons voir ce qui suit.

-Basiquement, "0" est fort pour $ I_x $ et $ I_y $

4.3 Le plus fort et le plus faible

J'ai recherché le nombre le plus fort et le nombre le plus faible avec ʻargmax / ʻargmin.

Le plus fort est naturellement "0", mais

allmax.png

Le stylo n'est-il pas trop large ... À propos, $ I_x = 0,259 $, $ I_y = 0,244 $, $ I_r = 0,251 $, qui sont les premiers dans tous les domaines. La personne qui a écrit ceci est fière.

Ensuite, je présenterai le plus faible de $ I_x $.

minIxa.png

C'est "2", mais c'est écrasé. En termes de calcul, je pense que c'est aussi le nombre le plus écrasé. Ça a l'air faible. ($ I_x = 0,013 $)

Et le plus faible de $ I_y $

minIy.png

C'est trop mince. Si vous appliquez une force latérale, il se cassera. ($ I_y = 0,0015 $ ← J'ai baissé le chiffre car il est trop petit)

Enfin, le plus faible de $ I_r $

minIx.png

À première vue, il est similaire au précédent "1", mais il est légèrement incliné. ($ I_r = 0,010 $) Les ensembles de données d'apprentissage automatique peuvent être uniques.

5. Expérience

Faisons une expérience.

J'ai construit un modèle théorique avec TensorFlow 2.0 et appris le GAN en appliquant la fonction de perte de l'équation (8) à Generator. Le modèle est ajouté en bonus à l'annexe. J'ai mis tout le code sur GitHub.

--Toutes les expériences sont effectuées en laboratoire (K80)

Version etc.

5.1 Divers paramètres et résultats de génération

5.1.1 Danmen-GAN

Le FID minimum est la valeur FID minimum atteinte lors de son entraînement. (Plus le FID est petit, mieux c'est.) De plus, la cible de comparaison du FID est l'image générée et les données d'apprentissage.

GAN-I_x-to-1.0 alpha (2).png

Le graphique montre les changements de $ I_x $, $ FID $ et $ \ frac {I_x} {FID} $ lorsque α est modifié (β = γ = 0). À partir de ce graphique, il devient clair qu'au lieu d'obtenir le moment secondaire transversal, nous sacrifions le FID.

Changement de l'image de sortie (β = γ = 0). Plus vous allez bas, plus la force verticale est forte.

\alpha production(Époque finale) FID minimum maximumI_x maximumI_y maximumI_r
\alpha=0 (GAN normal) _vanillaGAN_24000_image.png 36.0 0.109 0.090 0.083
0.1 _I_x01_24000_image.png 36.9 0.106 0.082 0.095
1.0 _I_x1_24000_image.png 32.8 0.103 0.077 0.090
5.0 _I_x5_24000_image.png 59.5 0.126 0.097 0.111
10.0 _I_x10_24000_image.png 69.4 0.145 0.116 0.130
25.0 _I_x25_24000_image.png 96.0 0.193 0.160 0.176
50.0 _I_x50_24000_image.png 135.8 0.249 0.212 0.230
75.0 _I_x+75_24000_image.png 180.4 0.317 0.278 0.297
100.0 _I_x100_24000_image.png 208.7 0.374 0.354 0.364

Après tout, "0" est fort. Je pense que c'est à cause du biais dans l'ensemble de données.

Même sans perte, une section transversale avec un moment secondaire de section efficace qui est 20% plus élevé que la moyenne $ I_x $ est générée, il semble donc que la force du GAN normal lui-même soit biaisée en premier lieu. Cela peut être dû au comportement de base du GAN, tel qu'il est sujet au bruit.

Si vous allez au niveau $ \ alpha = 50.0 $, ** il semble que vous puissiez générer la force de la classe aberrante des données d'origine en moyenne, donc je pense que cela peut être appliqué à l'expansion de données qui génère un petit nombre de données avec GAN * *. Par exemple, dans le cas des images diagnostiques médicales, il existe des images accentuées par la méthode de résonance magnétique nucléaire T1 / T2, mais en T1, la tumeur semble un peu blanche [^ T1], donc en appliquant une perte qui augmente la valeur de pixel de l'image. , Il est possible de créer une image générée avec une tumeur extrêmement volumineuse. Après cela, puisque les propriétés du cerveau etc. changent à l'extérieur (rainure externe et cortex cérébral) et à l'intérieur (kaiba et canal cérébral) de la section transversale, la tendance de la maladie devrait probablement changer. En faisant cela, j'ai pensé qu'il serait possible de générer une image avec une forme proche de la maladie en élargissant les données GAN en fonction de la maladie cible. (Je ne sais rien des soins médicaux, alors je pourrais dire quelque chose d'approprié ...)

Exemple de $ I_y $, $ I_r $

Paramètres production(Époque finale) FID minimum maximumI_x maximumI_y maximumI_r
\beta=25.0, \alpha=\gamma=0 _I_y+25_24000_image.png 122.2 0.180 0.178 0.179
\beta=75.0, \alpha=\gamma=0 _I_y+75_24000_image.png 160.8 0.267 0.284 0.275
\gamma=25.0, \alpha=\beta=0 _I_r+25_24000_image.png 113.2 0.181 0.165 0.173
\gamma=75.0, \alpha=\beta=0 _I_r+75_24000_image.png 170.5 0.285 0.284 0.285

Ceux-ci ont également un "0" fort. D'autres chiffres ont été publiés correctement, il semble donc peu probable qu'il s'agisse d'un effondrement de mode.

5.1.2 Chiffres en baisse

En appliquant la théorie de Danmen-GAN, le moment secondaire de section transversale souhaité peut être réglé à "0,0" et la résistance peut être réduite. Cela peut être exprimé par l'équation (9)

\mathcal{L}_{S} = \mathbb{E} \left[\| S(G(z))\|_{2}\right] \tag{9}

GAN-I_x-to-0.0 alpha (2).png

Ce graphique montre les changements dans $ I_x $ et FID, et $ \ frac {1} {I_x \ times FID} $ quand $ \ alpha $ est changé (β = γ = 0). La réduction du moment secondaire transversal se fait également au détriment du FID. En effet, l'écart par rapport à la distribution des données d'origine équivaut à une augmentation.

Changements dans l'image de sortie ($ \ beta = \ gamma = 0 $)

\alpha production(Époque finale) FID minimum le minimumI_x le minimumI_y le minimumI_r
0.1 _I_x-01_24000_image.png 38.6 0.093 0.058 0.076
1.0 _I_x-1_24000_image.png 40.5 0.091 0.058 0.073
5.0 _I_x-5_24000_image.png 35.3 0.084 0.050 0.067
10.0 _I_x-10_24000_image.png 36.4 0.086 0.053 0.070
25.0 _I_x-25_24000_image.png 30.0 0.069 0.042 0.056
50.0 _I_x-50_24000_image.png 41.5 0.062 0.033 0.048
100.0 _I_x-100_24000_image.png 48.6 0.055 0.026 0.040
500.0 _I_x-500_24000_image.png 112.4 0.043 0.013 0.028

Après tout, il y a une tendance à l'apparition de nombreux "1", qui sont à l'origine de faible intensité. De plus, je me sens mince.

L'échelle du paramètre a changé depuis le moment où le moment secondaire de la section transversale est renforcé, et il semble que cela soit moins affecté même s'il est appliqué fortement (probablement en raison du rapport de pixels).

Exemple de $ I_y $, $ I_r $

Paramètres production(Époque finale) FID minimum le minimumI_x le minimumI_y le minimumI_r
\beta=25.0, \alpha=\gamma=0 _I_y+25_24000_image.png 32.0 0.079 0.047 0.063
\beta=500.0, \alpha=\gamma=0 _I_y-500_24000_image.png 136.3 0.049 0.015 0.032
\gamma=25.0, \alpha=\beta=0 _I_r+25_24000_image.png 30.2 0.074 0.047 0.061
\gamma=500.0, \alpha=\beta=0 _I_r-500_24000_image.png 139.7 0.046 0.013 0.030

C'est une possibilité, mais je pense que si vous mettez une perte sur celui qui diminue l'intensité, ** le bruit sera supprimé et le FID sera amélioré **. En particulier, le calcul du moment secondaire de la section transversale a la propriété d'appliquer une forte perte au bord de l'écran, et CNN fait des choses suspectes telles que le rembourrage dans le traitement du bord de l'écran, il est donc possible que la compatibilité soit en maillage. Il y a. En particulier, le moment polaire secondaire de la section transversale $ I_r $ peut être efficace car il affecte tout le bord de l'écran.

Ce n'est peut-être qu'une coïncidence, alors je vais personnellement creuser plus profondément.

5.2 Moment de la deuxième section vs FID

Nous avons confirmé à quel point la montée du FID était supprimée par rapport à l'allongement du moment secondaire de la section transversale. $ \ frac {I_x} {FID} $ obtient le plus gros en formation. Il semble que le FID explose en réponse à une légère augmentation du moment secondaire de la section transversale, donc au lieu de gagner en force, il s'écarte de la distribution des données d'origine.

\alpha \frac{I_x}{FID}
\alpha=0.0 0.00250
\alpha=0.1 0.00250
\alpha=1.0 0.00277
\alpha=5.0 0.00207
\alpha=10.0 0.00220
\alpha=25.0 0.00180
\alpha=50.0 0.00150
\alpha=75.0 0.00130
\alpha=100.0 0.00120
ones 0.00257

ones est la section transversale quand tout est 1.0. Le FID à ce moment était de 394,5. Dans ce cas, les performances de $ \ frac {I_x} {FID} $ seront meilleures si toute la sortie est 1.0 ou si la sortie est simple. Au contraire, si vous créez une couche pour calculer le FID et concevoir $ \ frac {I_x} {FID} $ comme une perte, il semble intéressant que des résultats différents ressortent à nouveau. (J'ai pu créer un calque FID [^ fidlayer], mais je l'ai arrêté car la partie qui trouve la racine carrée de la matrice est devenue un goulot d'étranglement dans le calcul. En principe, c'est possible.)

Au final, nous avons réussi à générer plus que la section la plus forte de l'ensemble de données, mais nous n'avons pas encore confirmé la génération d'une section plus faible que la plus faible (même si nous pourrons peut-être faire plus de pertes).

6. Impression avec une imprimante 3D

Comme c'est un gros problème, imprimons-le avec une imprimante 3D et vérifions la force.

J'ai utilisé un modèle appelé Ender-3, qui est de 20 000 à 30 000 sur les sites d'achat en ligne.

6.1 Exécutez TensorFlow 2.0 avec Blender et générez automatiquement des polygones numériques

Du côté de Blender, la génération automatique est effectuée comme ceci. L'image ci-dessous est le premier "0" dans les données MNIST.

1.png

La partie correspondant au pixel est automatiquement générée avec ʻadd_cube`. (Parce que la méthode est assez rude, il semble que la boutique 3D se fâche)

L'image ci-dessous est un nombre semblable à "8" généré par Danmen-GAN avec une pénalité de $ \ alpha = 75 $. Un module appelé bpy vous permet de manipuler l'API de Blender en Python, donc Python sur Blender charge le modèle entraîné de TensorFlow et le génère à la volée. Très pratique.

2.png

Les valeurs de pixel inférieures à "0,25" sont "0", les valeurs de pixels comprises entre "0,25 et 0,75" sont perforées aléatoirement aux 3/4 de la zone (légèrement perforées pour réduire la force) et les valeurs de pixels supérieures à "0,75" Est une heuristique avec 1.0 pour gérer les pixels ambigus pour le moment.

Les pièces qui ne sont pas liées à la résistance sont supprimées manuellement. (Pour améliorer l'efficacité d'impression)

3.png

Ce qui suit est la coupe transversale après préparation.

J'ai fait quelque chose comme un fragment sous le numéro avec l'image d'un piédestal pour fixer les membres. Cela se fait en inversant les pixels du nombre (1.0 --img), en les arrondissant avec np.ceil (), en appliquant le rétrécissement scikit-image (skimage.morphology.binary_erosion), en ajustant et C'est un ensemble avec l'instruction for.

Ci-dessous se trouve l'écran d'un logiciel appelé Cura qui génère Gcode (commande de contrôle des buses d'imprimante 3D) pour les imprimantes 3D.

À l'origine, je l'ai fait avec une longueur totale de 60 mm, mais comme le temps d'impression était affiché à 3-4 heures, je l'ai réduit de 40% et je l'ai imprimé. (Cura peut effectuer des opérations de modèle de base telles que la mise à l'échelle, donc Blender n'a pas à se soucier de l'échelle.)

6.2 Résultat d'impression

Le côté gauche est "0" et le côté droit est "8". (J'ai remarqué ici que la base de "8" est séparée à gauche et à droite.)

IMG_4978.JPG

IMG_1209.JPG

IMG_6556.JPG

(J'ai remarqué que "8" est devenu stable lorsque je l'ai retourné.)

C'est comme ça.

6.3 Endurance

Faisons également un test d'endurance. Je n'ai pas fait un léger mouvement dans le test de résistance à moitié cuit, alors j'ai finalement mis mon poids dessus car il n'y avait pas d'autre moyen.

"0" dans l'ensemble de données

ezgif-2-632e2eb25ad3-compressor.gif

Numéro généré

ezgif-2-aaaf95b89279-compressor.gif

Les deux se sont cassés ... (Je regrette que si j'avais mis du poids sur les deux en même temps, j'aurais pu trouver le plus fort. Pour le moment, le résultat de la génération de GAN est basé sur une graine aléatoire, il est donc facile à reproduire. )

Lorsque j'ai vérifié la section transversale, les deux étaient cassés le long de la surface stratifiée du filament de l'imprimante 3D.

7. Conclusion

Conclusion

Nouvelle hypothèse obtenue dans l'expérience

8. Conclusion

Cette fois, je l'ai essayé avec MNIST pour faciliter la compréhension et alléger la complexité de l'apprentissage du GAN, mais je pense qu'il peut être théoriquement appliqué à d'autres données.

De plus, comme ceux-ci sont biaisés, je pense qu'il est nécessaire de les conditionner avec un GAN conditionnel, etc. afin d'obtenir le nombre souhaité tout en manipulant la force. En tant qu'application, il devrait être logiquement possible de donner des informations de résistance à la partie de conditionnement du GAN conditionnel et de générer une section transversale en fonction de cette résistance.

Enfin, en les appliquant, en utilisant FEM (= méthode des éléments finis), en calculant l'équilibre des forces structurelles et en ajoutant des pertes, je pense que cela peut également être appliqué aux structures tridimensionnelles. (S'il vous plaît laissez-moi savoir si vous l'avez déjà)

Je pense que cela va bien avec "l'alchimie des polices StackGAN [^ nardtree]" que faisait nardtree.

9. Merci

Shichiya-san (@ sitiya78): L'imprimante 3D est une liste de souhaits personnelle d'Amazon. Merci beaucoup pour cette section. Je ne vous remercierai jamais assez.

10. Code expérimental

Ici: mettez tout sur https://github.com/p-geon/DanmenGAN.

Appendix

Prime

A. À propos de la structure des couches de TensorFlow

Décrit la structure des couches de TensorFlow 2.0. En gros, je vais expliquer trois choses, Générateur / Discriminateur / Générateur et Discriminateur. Pour les passionnés.

A-1. Generator

(Cliquez sur l'image pour voir les détails.)

Generator est à peu près un graphique qui génère des images ( Generator </ font>), un graphique normalisé ( Normaliser </ font>) et un graphique qui calcule la densité ( Normaliser </ font>). Densité </ font>), Graphique pour trouver le moment secondaire de la section transversale $ I_x $ ( Ix </ font>), Recherche du moment secondaire de la section transversale $ I_y $ Il peut être divisé en un graphique ( Iy </ font>) et un graphique $ I_r $ ( Ir </ font>) pour trouver le moment polaire secondaire de la section transversale.

Générateur: graphe de génération d'image ~ graphe de normalisation

Voici le code du générateur d'images à la normalisation du générateur.

Les bases sont les mêmes que celles du GAN normal. De plus, il y a beaucoup d'informations sur le GAN sur le net, je vais donc les omettre ici.

«smoa» est une classe pour calculer le moment secondaire de section transversale, et à l'intérieur de cette classe, le moment secondaire de section transversale de calcul de densité est calculé.

def build_generator(params, smoa):
    # Noise
    z = z_in = tf.keras.layers.Input(shape=(params.NOISE_DIM, ), name="noise")

    # (NOISE_DIM, ) -> (1024, )
    x = tf.keras.layers.Dense(1024)(z)
    x = tf.keras.layers.LeakyReLU(alpha=0.2)(x)
    x = tf.keras.layers.BatchNormalization(momentum=0.8)(x)

    # (1024, ) -> (7*7*64, ) -> (7, 7, 64)
    x = tf.keras.layers.Dense(7*7*64)(z)
    x = tf.keras.layers.LeakyReLU(alpha=0.2)(x)
    x = tf.keras.layers.BatchNormalization(momentum=0.8)(x)
    x = tf.keras.layers.Reshape(target_shape=(7, 7, 64))(x)

    # (7, 7, 64) -> (14, 14, 32)
    x = tf.keras.layers.Conv2DTranspose(32, kernel_size=(5, 5)
        , padding='same', strides=(2, 2), use_bias=False, activation=None)(x)
    x = tf.keras.layers.BatchNormalization(momentum=0.8)(x)
    x = tf.keras.layers.LeakyReLU(alpha=0.2)(x)

    # (14, 14, 128) -> (28, 28, 1)
    x = tf.keras.layers.Conv2DTranspose(1, kernel_size=(5, 5)
        , padding='same', strides=(2, 2), use_bias=False, activation=None)(x)
    img = tf.math.tanh(x)
    y = tf.keras.layers.Lambda(lambda x: x, name="generated_image")(img) #Comme img est utilisé plus tard, changez le nom de la variable en y

    """
Calcul du moment secondaire transversal(Cela devient un graphe comme ResNet)
    """
    # range: [-1.0, 1.0] -> [0.0, 1.0]
    img = (img + 1.0)/2.0
    I_x, I_y, I_r = smoa.calc_second_moment_of_area(img)

    return tf.keras.Model(inputs=z_in, outputs=[y, I_x, I_y, I_r])

Générateur: Graphique de calcul de densité ~ Graphique de calcul de moment secondaire de section

Ce qui suit est une méthode de construction de graphe qui obtient le moment secondaire de la section transversale uniquement par calcul tensoriel.

Commencez par calculer les constantes dans le graphe de calcul et préparez d'abord le tenseur en utilisant tf.constant () comme variable de classe.

Ceux à utiliser sont self.arange_x, self.arange_y, self.distance_matrix_x, self.distance_matrix_y, self.norm_I_x, self.norm_I_y.

En tant que description de la variable

--self.arange_x / self.arange_y: vecteurs ordonnés simples --self.distance_matrix_x / self.distance_matrix_y: Tensol représentant la distance de l'axe --self.norm_I_x / self.norm_y: Moment secondaire transversal maximal pour la normalisation (scalaire)

Ce sera.

class SecondMomentOfArea:
    def __init__(self, img_shape=(28, 28)):
        distance_vector_x = np.asarray([0.5+d for d in range(img_shape[1])])
        distance_matrix_x = np.tile(distance_vector_x, (img_shape[0], 1))
        distance_matrix_y = distance_matrix_x.T
        """
Matrice de normalisation
        """
        matrix_for_norm_I_x = np.tile(np.abs(arange_y - img_shape[0]/2.0), (img_shape[1], 1)).T
        norm_I_x = np.sum(matrix_for_norm_I_x)

        matrix_for_norm_I_y = np.tile(np.abs(arange_x - img_shape[1]/2.0), (img_shape[0], 1)).T
        norm_I_y = np.sum(matrix_for_norm_I_y)

        """
        to TFconstant
        """
        self.arange_x = tf.constant(arange_x, dtype=tf.float32) # (28, )
        self.arange_y = tf.constant(arange_y, dtype=tf.float32) # (28,)
        self.distance_matrix_x = tf.constant(distance_matrix_x[np.newaxis, :, :, np.newaxis], dtype=tf.float32) # (1, 28, 28, 1)
        self.distance_matrix_y = tf.constant(distance_matrix_y[np.newaxis, :, :, np.newaxis], dtype=tf.float32) #(1, 28, 28, 1)
        self.norm_I_x = tf.constant(norm_I_x, dtype=tf.float32) #()
        self.norm_I_y = tf.constant(norm_I_y, dtype=tf.float32) #()

La distance_matrix est normalisée, «[0,:,:, 0]» est découpé et la figure est la suivante.

distance_matrix_x distance_matrix_y

J'écrirai la suite du cours précédent.

Afin de calculer le moment secondaire de la section transversale, il est d'abord nécessaire de calculer le centre de gravité (axe neutre) de la section transversale. Calculez ensuite la densité (total de tous les pixels / nombre de pixels de l'image) pour calculer l'axe neutre.

Tout d'abord, multipliez la «distance_matrix» et la valeur de pixel de l'image pour chaque élément pour obtenir le moment. Ensuite, le moment est corrigé à l'aide de la densité, et lorsque les moments sont pairs, l'axe neutre est au centre de l'image.

Après avoir calculé l'axe neutre, créez un tenseur qui représente la distance à l'axe neutre dans l'ordre de soustraction → valeur absolue → transformation → liage → axe d'addition.

Après cela, calculez le tenseur et l'image représentant la distance en multipliant chaque élément, calculez le total et normalisez-le, et le calcul du moment quadratique de la section transversale est terminé.

Le calcul du moment secondaire du pôle transversal $ I_r $ est normalisé en ajoutant $ I_x $ et $ I_y $ tel que défini de sorte que le maximum soit 1,0.

tf.keras.layers.Lambda (lambda x: x) (・) ne fait rien, mais est écrit pour améliorer la visibilité des couches.

    def calc_second_moment_of_area(self, img): # (None, 28, 28, 1)
        """
Calcul de l'axe neutre
        """
        density = (tf.reduce_sum(img, axis=[1, 2], keepdims=True)/(img.shape[1]*img.shape[2]))
        # (1, 28, 28, 1) x (None, 28, 28, 1) -> (None, 28, 28, 1)
        x_moment = tf.math.divide_no_nan(tf.math.multiply(self.distance_matrix_x, img), density)
        y_moment = tf.math.divide_no_nan(tf.math.multiply(self.distance_matrix_y, img), density)

        # (None, 28, 28, 1) -> (None, )
        neutral_axis_x = tf.math.reduce_mean(x_moment, axis=[1, 2])
        neutral_axis_y = tf.math.reduce_mean(y_moment, axis=[1, 2])

        """
Moment secondaire sectionnel(Verticale)
        I_x = ∫_A y^2 dA
        """
        # sub: (None, 28, ) - (None, ) -> abs: (None, 28)
        dy = tf.math.abs(self.arange_y - neutral_axis_y)
        # (None, 28) -> (None, 1, 28)
        dy = tf.reshape(dy, shape=[-1, img.shape[1], 1])
        # (None, 1, 28) -> (None, 28, 28)
        matrix_x = tf.tile(dy, multiples=[1, 1, img.shape[2]])
        # (None, 28, 28) -> (None, 28, 28, 1)
        matrix_x = tf.expand_dims(matrix_x, 3)
        # (None, 28, 28, 1)x(None, 28, 28, 1) -> (None, 28, 28, 1) -> (None,)
        I_x = tf.math.reduce_sum(tf.math.multiply(matrix_x, img), axis=[1, 2])/self.norm_I_x

        """
Moment secondaire sectionnel(côté)
        I_y = ∫_A x^2 dA
        """
        # sub: (None, 28, ) - (None, ) -> abs: (None, 28)
        dx = tf.math.abs(self.arange_x - neutral_axis_x)
        # (None, 28) -> (None, 28, 1)
        dx = tf.reshape(dx, shape=[-1, 1, img.shape[2]])
        # (None, 1, 28) -> (None, 28, 28)
        matrix_y = tf.tile(dx, multiples=[1, img.shape[1], 1])
        # (None, 28, 28) -> (None, 28, 28, 1)
        matrix_y = tf.expand_dims(matrix_y, 3)
        # (None, 28, 28, 1)x(None, 28, 28, 1) -> (None, 28, 28, 1) -> (None,)
        I_y = tf.math.reduce_sum(tf.math.multiply(matrix_y, img), axis=[1, 2])/self.norm_I_y
        """
Moment polaire secondaire de la section(2 pour la normalisation.Diviser par 0)
        """
        I_r = (I_x + I_y)/2.0
        """
        Lambda
        """
        I_x = tf.keras.layers.Lambda(lambda x: x, name="I_x")(I_x)
        I_y = tf.keras.layers.Lambda(lambda x: x, name="I_y")(I_y)
        I_r = tf.keras.layers.Lambda(lambda x: x, name="I_z")(I_r)

        return I_x, I_y, I_r

Lors de la génération du côté Blender, il n'est pas nécessaire de calculer le moment secondaire de la section transversale, vous pouvez donc générer trois tenseurs de (Aucun,) avec une fonction appropriée. Je l'ai traité avec tf.reduce_sum (img).

A-2. Discriminator

Discriminator n'est pas différent d'un GAN ordinaire. C'est un style DCGAN classique.

A-3. Generator & Discriminator

Nous allons également créer un graphique qui combine le générateur et le disctiminateur pour former le GAN.

L'entrée est uniquement du bruit z, et la sortie est les probabilités prédites p et ʻI_x, ʻI_y, ʻI_r` sorties par Discriminator.

Les trois types de moments secondaires transversaux peuvent être calculés et les coefficients peuvent être ajustés lorsque la perte est appliquée, de sorte que vous pouvez apprendre le GAN normal et renforcer les moments secondaires transversaux. .. Si vous voulez affaiblir le moment secondaire de la section transversale, vous pouvez changer la valeur cible de $ I $ de «1.0» à «0.0».

Matériel de référence

Principalement mes notes que j'ai écrites pour faire ceci

--Lors de l'utilisation de tf.print (), le contenu du tenseur ne peut pas être affiché dans une f-string: https://qiita.com/HyperPigeon/items/007c5adca9a4e78bc6d1

  • Premiers secours lorsque Nan apparaît dans tf.linalg.sqrtm () de TensorFlow 2.0 Frechet Inception Distance (FID) calcul: https://qiita.com/HyperPigeon/items/f3f20f480269e2594724 --AttributeError: l'objet 'dict' n'a pas d'attribut'name 'lors de l'utilisation de tf.keras.utils.plot_model () dans TensorFlow 2.0 et sa solution: https://qiita.com/HyperPigeon/items/fb22b555e76b52b3d688 --Solution lorsque la session Colaboratory (Jupyter Notebook) plante avec tensorflow_addons (tfa.image.rotate): https://qiita.com/HyperPigeon/items/94831b8a9af75527b67b
  • Notation des dimensions (mètres, etc.) dans Blender 2.8 et versions ultérieures: https://qiita.com/HyperPigeon/items/c5d2ec3264e8fd14d167 --Installez TensorFlow 2.0 (CPU) avec Blender 2.8.2, HelloWorld (Windows10): https://qiita.com/HyperPigeon/items/e6c37dc143039b75d0e4

  1. LeCun, Yann and Cortes, Corinna. MNIST handwritten digit database, 2010. ↩︎

  2. Ian Goodfellow, Jean Pouget-Abadie, Mehdi Mirza, Bing Xu, David Warde-Farley, Sherjil Ozair,Aaron Courville, and Yoshua Bengio. Generative Adversarial Networks. In NIPS, 2014. ↩︎